首先描述一下我想實現的什么東西。以前我發版是通過命令手動打包打鏡像,然后推送到倉儲里面對,然后再在服務器上從倉庫里面拉最新的鏡像。然而我看VS里面項目其實有可以直接發布到自己的容器注冊表(我理解就是容器倉庫),所以就研究了研究
1、首先肯定是先准備一個項目,項目其實很簡單,沒什么特別的內容,唯一說明的一下是,因為我覺得既然使用了IOC,Web就不應該再依賴Service層,所以我的Web只引用了IService層,這導致的問題就是我的Service的dll文件我需要手動拷貝進web的bin目錄下,為了簡化操作,於是我寫了兩個腳本。一個Bat(Windows下使用)和一個sh文件(Linux使用)
在建項目的時候,開始我直接建立的Web項目,添加了dockerfile支持。后續在點擊發布按鈕的時候可以看到日志執行了docker的命令:
docker build -f "C:\Users\txb\source\repos\CBest.B2BSupply\CBest.B2BSupply.Web\Dockerfile" --force-rm -t cbestb2bsupplyweb --label "com.microsoft.created-by=visual-studio" --label "com.microsoft.visual-studio.project-name=CBest.B2BSupply.Web" "C:\Users\txb\source\repos\CBest.B2BSupply"
如果直接新建的Web工程,它的工程環境會在web那一層里面所以導致的問題就是dockerfile里面的copy命令回找不到其他工程的工程文件。指定目錄貌似也沒有成功過,我也沒找到這個命令在哪兒配置的。
所以我的做法是先新建解決方案。然后再解決方案里面添加各個工程項目。
build.cmd內容,主要內容是判斷模式,如果debug就用dotnet build ,release模式就用dotpublish
echo off if %1 == "Debug" ( dotnet build -c %1 -o %2 ../CBest.B2BSupply.Service ) else ( dotnet publish -c %1 -o %2 ../CBest.B2BSupply.Service ) echo on
Linux的腳本也差不多類似
echo "Linux bat buiding is starting" if [$1 == "Debug"] then dotnet build -c $1 -o $2 ../CBest.B2BSupply.Service else then dotnet publish -c $1 -o $2 ../CBest.B2BSupply.Service fi
以上的操作思路上一直沒出現問題,唯一出現的問題就是再VS生成事件上的問題,因為Linux和windows的腳本語法不一樣。所以我寫了cmd和sh兩個,我需要對操作系統判斷執行那個腳本,好像這個在這里沒法實現,於是我又想了一個曲線救國的辦法。我寫了一個小程序程序的主要功能就是判斷當前運行的操作系統去執行不同的腳本程序
class Program { static int Main(string[] args) { Console.WriteLine("ExcuteShell Is Running......."); if (args.Length < 1) { Console.WriteLine("無腳本文件"); return 0; } string batName = Path.GetFileName(args[0]); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { batName = batName + ".cmd"; } else { batName = batName + ".sh"; } try { var startInfo = new ProcessStartInfo() { FileName = batName, CreateNoWindow = false }; for (var i = 1; i < args.Length; i++) { startInfo.ArgumentList.Add(args[i]); } Process process = new Process() { StartInfo = startInfo }; process.Start(); Console.WriteLine(process.ExitCode); Console.WriteLine(process.StandardOutput); } catch (Exception ex) { Console.WriteLine(ex.Message); return 0; } Console.WriteLine("ExcuteShell Is Ending......."); return 0; } }
這里又遇到問題了。。編譯生成單文件的exe要門用於Windows要么用於Linux必須指定什么identityName(具體忘記什么了).所以編譯成Exe程序我又存在那個腳本的問題,一個Linux程序,一個Windows程序,還是沒解決我的問題。編譯成跨平台的dll文件,就需要一堆其他的文件,沒有單個文件方便,所以沒有好的辦法,我選擇了一個這種的辦法。把工具生成以后放入解決方案的tools目錄下(放在統一的目錄也好找)
最終我的生成事件命令:
執行腳本的小程序接受三個參數,
第一個是腳本名字,不用待后綴,根據操作系統判斷回加上.cmd(windows下)和.sh(liinux下),
后面的參數是腳本的所需要的參數。一個是編譯的方式(Debug或Release),一個是生成的目標目錄,就是web項目的目錄
dotnet ../tools/excuteshell/ExcuteShell.dll $(ProjectPath)/pp $(ConfigurationName) $(TargetDir)
(我后面才反應過來,既然都是使用dotnet命令,我干嘛不直接在生成事件里面寫dotnet build命令,用個錘子的腳本啊。還寫了一個沒什么用處的小程序)
所以修改后的生成事件命令:
dotnet build -c $(ConfigurationName) -o $(TargetDir) ../CBest.B2BSupply.Service
2、工程文件搞定,然后就是發布的配置
新建配置,選擇Docker容器注冊表,下一步
選擇其他DOckers容器注冊表,如果沒有私有的容器倉庫,可以選擇Docker Hub,不過我想應該公司都有一個自己的容器倉庫把。畢竟把項目放到其他外網不安全肯定是不安全的。
配置完成容器地址,點擊完成,發布的配置就結束了:
用戶名帶上,密碼根據你的倉儲要不要密碼,可寫可不寫,不帶用戶名,好像我是發布失敗了
滿懷希望的點擊publish,哦豁一連串的報錯開始了,什么Copy找不到文件,什么編譯找不到剛配置的腳本命令各種問題。簡單說一下遇到得問題
遇到得第一個問題。就是在build dockerfile得時候里面會把代碼拷貝到docker進行編譯。在執行COPY指令得時候回提示找不到其他項目得文件。嘗試了很多解決方法。指定相對目錄,指定絕對目錄都不行,
后面得解決方法是先建立解決方案文件再往解決方案里面添加工程文件。一試還真成功了
后面遇到得第二個問題就是sh和bat得問題。window只識別bat文件,Linux只識別sh文件。開始再overstack上看到一個大佬說不用添加后綴會根據操作系統自動查找項目下能夠執行得腳本文件,嘗試過。windows進行build是沒問題得。但是當我點擊VS上得publish得時候就會提示找不到腳本文件。我得解決方法就繞道了寫程序來判斷操作系統調用不同得腳本文件
第三個就是nuget還原得問題。巨慢而且還經常掉線。偶爾行偶爾不行得。這個就看人品了,我切換了一個國內nuget源,貌似好很多。具體操作就是再dockerfile里面執行還原項目得時候指定一下國內源就可以了。還有她們說訪問私有源也可以通過這個方法呢。
RUN dotnet restore "CBest.B2BSupply.Web/CBest.B2BSupply.Web.csproj" -s "https://nuget.cdn.azure.cn/v3/index.json"
上面三個問題解決以后,這個架子就搭建得差不多了。。然后激動得點擊了publish按鈕。
反正有點耗時。特別耗時。不過成功了,也還是值得欣慰。一步操作編譯,生成,構建鏡像,發送鏡像庫,方便是方便。但是的確是慢。也許用jekins實現自動化會好點,當個研究也是好得。