前言
最近公司的項目打算移植到.Net Core平台,所以調研了一下.Net Core在Linux下的安裝部署。本篇文章會一步步的描述從安裝到配置到部署的全部過程。在文章的結構和內容里,筆者借鑒了很多其他博文的內容,但感覺其他博文中都只是實現了一部分或者沒有將配置內容寫全。筆者做的是整理一下自己的實際部署過程。
目錄
步驟
- 一台Linux服務器:筆者用的是VMWare的虛擬機模擬的環境,有條件的朋友可以使用真實服務器作為部署環境
- Linux終端:筆者用的是MobaXterm
$ sudo adduser docker_user
$ sudo usermod -aG sudo docker_user $ exit

$ sudo apt-get update $ sudo apt-get upgrade $ sudo apt-get dist-upgrade $ sudo reboot
我們要運行.Net Core的項目,自然要安裝.Net Core的環境啦。這里微軟提供了大部分Linux版本的安裝方案,我使用的是Ubuntu16.04,所以以下代碼是針對這個系統版本的,如果你使用的是其他版本可以參考(https://docs.microsoft.com/en-us/dotnet/core/linux-prerequisites?tabs=netcore2x)
// 注冊微軟產品Key為被信任的 $ curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg $ sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg // 設置所需要的版本主機包 $ sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > /etc/apt/sources.list.d/dotnetdev.list' // APT支持Https $ sudo apt-get install apt-transport-https $ sudo apt-get update // 安裝.Net Core SDK $ sudo apt-get install dotnet-sdk-2.0.3 // 檢查安裝是否成功 $ dotnet --version
因為是Demo項目,所以就在用戶根目錄下創建一個文件夾,將該文件夾作為項目的根目錄。
5.1 創建項目
$ cd ~/ $ mkdir helloworld $ cd helloworld $ dotnet new mvc

5.2 發布項目
$ dotnet restore
$ dotnet publish -c Release

5.3 運行發布好的程序
通過上面的截圖我們發現,發布完的程序和在PC平台上的差不多,是在bin/Release的目錄下。我們先移動到這個目錄,然后用"dotnet"命令運行這個Demo
$ cd bin/Release/netcoreapp2.0/publish/ $ dotnet helloworld.dll

執行命令以后,終端會如上圖所示。這個時候就說明程序已經跑起來了。倒數第二行則說明了,程序默認的端口號是5000。這個時候我們就可以通過服務器IP+端口號5000訪問這個網站了。(注:如果是外網訪問,需要在防火牆打開5000端口的權限。這個就不在本文中擴展了。)
筆者是通過開啟另一個終端來測試程序是否正常的,結果如下:
// 通過wget請求網站 $ wget http://localhost:5000

走到這一步,有不少同學就發現了。現在的程序是需要我們始終打開終端才能保證網站可以被訪問的,那接下來我們要做的就是將這個網站部署成一個自定義服務。讓網站可以在后台進程中運行。
6.1 准備運行目錄
按照Linux部署習慣,我們在var目錄下創建一個www文件夾,並將剛才發布的Demo放到該目錄下
$ cd /var $ sudo mkdir www $ cd www $ sudo mkdir helloworld $ cd helloworld $ sudo cp -r ~/helloworld/bin/Release/netcoreapp2.0/publish/* .
6.2 創建服務配置文件
$ cd /etc/systemd/system/ $ sudo touch dotnet-helloworld.service
6.3 編寫服務配置文件
$ sudo vi dotnet-helloworld.service
先通過vi進入該文件(注:vi是Linux下最常用的文本編輯器之一,如果對vi不了解,可以自行百度,這里就不擴展了)。進入編輯后,將以下代碼寫入配置文件
[Unit] Description=DotNet Core HelloWorld Running on Ubuntu [Service] WorkingDirectory=/var/www/helloworld // 工作目錄,這里我們寫的是剛才創建的網站工作目錄 ExecStart=/usr/bin/dotnet /var/www/helloworld/helloworld.dll // 服務的實際執行命令 Restart=always RestartSec=10 SyslogIdentifier=dotnet-example User=docker_user // 已docker_user的身份啟動 Environment=ASPNETCORE_ENVIRONMENT=Production Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false [Install] WantedBy=multi-user.target
上面這段配置文件我是參考微軟官方的部署文檔寫的(文檔鏈接)
6.4 啟動服務
$ sudo systemctl enable dotnet-helloworld.service $ sudo systemctl start dotnet-helloworld.service
6.5 檢查服務狀態
$ sudo systemctl status dotnet-helloworld.service
當服務啟動后,運行status命令查看服務狀態時,會返回服務執行的日志,終端會顯示類似於下圖的代碼。

這段代碼和我們之前直接用命令行啟動dotnet項目是相似,這也就說明我們的服務部署成功了。我們再使用wget驗證,同樣可以訪問這個網站了。
7. Nginx反向代理
做到這里,.Net Core項目的部署已經差不多了。接下來我們就通過Nginx進行反向代理。
7.1 安裝Nginx
// 安裝命令 $ sudo apt-get install nginx // 完成安裝后檢查安裝是否成功 $ nginx -v
7.2 配置反向代理
// 移動到Nginx配置文件夾 $ cd /etc/nginx/conf.d/ // 創建代理配置文件 $ sudo touch helloworld.conf // 編輯配置文件 $ sudo vi helloworld.conf // 配置內容 server { listen 80; location / { proxy_pass http://localhost:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } } // 測試配置 $ sudo nginx -t // 重新加載配置 $ sudo nginx -s reload
當完成這一步后,我們就可以在瀏覽器里直接輸入服務器的IP地址來訪問Demo網站了。

注:這里有一個小坑,Nginx有一個默認配置文件,文件路徑在:/etc/nginx/sites-available下。文件名是default。如果訪問的時候打開的不是上面這個網站,那需要到這個配置文件下,把所有的配置都注釋掉,再重新reload一下Nginx。
通過上面的教程,大家已經可以在自己電腦上訪問Linux服務器上的.Net Core項目了。接下來我們將.Net Core項目放到Docker下運行,並同樣通過Nginx方向代理,使我們能訪問到.Net Core項目。
8.1 卸載舊版本Docker
因為Ubuntu系統可能自帶Docker,所以在安裝新版Docker前先將舊版的Docker清楚干凈
$ sudo apt-get remove docker \ docker-engine \ docker.io
8.2 安裝
$ sudo apt-get update // 由於apt源使用 HTTPS 以確保軟件下載過程中不被篡改。因此,我們首先需要添加使用HTTPS 傳輸的軟件包以及 CA 證書。 $ sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ software-properties-common // 鑒於國內網絡問題,強烈建議使用國內源,官方源請在注釋中查看。 // 為了確認所下載軟件包的合法性,需要添加軟件源的 GPG 密鑰。 $ curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add - // 官方源 // $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - // 向 source.list 中添加 Docker 軟件源 sudo add-apt-repository \ "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu \ $(lsb_release -cs) \ stable" $ sudo apt-get update // 執行安裝命令 $ sudo apt-get install docker-ce
8.3 啟動Docker服務
$ sudo systemctl enable docker $ sudo systemctl start docker
8.4 建立Docker用戶組
默認情況下,docker命令會使用 Unix socket 與 Docker 引擎通訊。而只有 root 用戶和 docker 組的用戶才可以訪問 Docker 引擎的 Unix socket。出於安全考慮,一般 Linux 系統上不會直接使用 root 用戶。因此,更好地做法是將需要使用 docker 的用戶加入 docker 用戶組。
// 建立docker用戶組,這行命令執行的時候可能會報該用戶組已存在。如果報這個錯,可以直接跳過這條命令。 $ sudo groupadd docker // 將當前用戶加入docker用戶組 $ sudo usermod -aG docker $USER
執行完這條命令后,退出終端重新登錄一下。就可以使用docker命令來管理docker了。
8.5 鏡像加速器配置
鏡像(image)是docker的一個基礎元素,但當我們在國內的網絡環境中拉取Docker Hub(官方Docker鏡像庫)鏡像時會變得比較困難,這時我們就可以配置鏡像加速器。這里我使用的是Docker官方提供的國內加速器服務。
// docker文件夾默認是只允許root訪問的。這里筆者偷個懶就直接開放docker的文件夾權限了。 sudo chmod 777 /etc/docker cd /etc/docker // 創建並編輯加速器源 sudo touch daemon.js sudo vi daemon.js // 文件內容 { "registry-mirrors": [ "https://registry.docker-cn.com" ] } // 重啟服務 $ sudo systemctl daemon-reload $ sudo systemctl restart docker
9.1 拉取.Net Core鏡像
$ sudo docker pull microsoft/dotnet
9.2 修改Demo程序
之前我們用的是默認的Demo程序運行,程序是運行在5000端口上的,在我們的實際環境中,不可能每個服務都用同一個端口號,所以這次我們將端口好做一個小變動。
// 移動到最開始我們創建的Demo中。編輯Program.cs // $ cd ~/helloworld // $ vi Program.cs
內容為
namespace helloworld { public class Program { public static void Main(string[] args) { BuildWebHost(args).Run(); } public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .UseUrls("http://*:10001") // 使用10001作為程序運行時端口 .Build(); } }
完成之后,我們重新發布
$ dotnet restore
$ dotnet publish -c Release
9.3 編寫Dockerfile
// 移動到發布目錄 $ cd ~/helloworld/bin/Release/netcoreapp2.0/publish/// 創建Dockerfile $ sudo touch Dockerfile // 編輯Dockerfile $ sudo vi Dockerfile
以下是Dockerfile的內容
// 基於.Net Core鏡像來構建我們的鏡像 FROM microsoft/dotnet // 將程序復制到鏡像中的publish目錄 COPY . /publish // 定義工作目錄為publish WORKDIR /publish // 設置Docker容器對外暴露的端口 EXPOSE 10001 // 執行dotnet命令 CMD ["dotnet", "helloworld.dll"]
9.4 構建Docker鏡像
$ docker build -t helloworld:1.0 .
注意最后有一個"."

9.5 運行構建的鏡像
$ docker run --name helloworld -d -p 10001:10001 helloworld:1.0

9.6 修改Nginx配置
在本文前半段,我們讓Nginx代理了5000端口,現在我們把他改為10001。
// 編輯之前創建的Nginx配置 $ cd /etc/nginx/conf.d/ $ vi helloworld.conf // 只需要修改代理的端口就行 server { listen 80; location / { proxy_pass http://localhost:10001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $http_host; proxy_cache_bypass $http_upgrade; } } // 重載Nginx $ sudo nginx -t $ sudo nginx -reload
好了。大功告成,我們現在又可以在瀏覽器中用服務器IP直接訪問到Demo網站了。
總結
這次學習的過程,總共花了大概兩天時間,反反復復看了很多其他的教程。但大部分教程都感覺要么沒說清楚,要么就是缺少某個步驟而導致最后運行不起來,所以在完成配置以后,決定寫下這篇文章,算是給自己一個交代。也希望可以幫到各位看客。
