Linux中以單容器部署Nginx+ASP.NET Core
引言
正如前文提到的,強烈推薦在生産環境中使用反向代理伺服器轉發請求到Kestrel Http伺服器,本文将會實踐将Nginx --->ASP.NET Core 部署架構容器化的過程。
Nginx->ASP.NET Coe部署架構容器化
在Docker中部署Nginx--->ASP.NETCore 有兩種選擇, 第一種是在單容器内部署Nginx+ASP.NET Core, 這是本文着重要講述的,另外一種是以獨立容器分别部署Nginx和ASP.NET Core,容器之間通過Docker内建的network bridge完成通信(請關注後續博文)。
本次實踐将會使用.NET Core CLI 建立預設的web應用
1
2
3
4
5
mkdir app
cd app
dotnet new web
dotnet restore
dotnet build
之後将項目釋出到指定目錄(dotnet publish), 釋出産生的檔案将會用于鏡像打包。
建構鏡像
本次将以 ASP.NETCore Runtime Image【mcr.microsoft.com/dotnet/core/aspnet:2.2】 作為基礎鏡像, 該鏡像包含.NET Core Runtime、ASP.NET Core架構元件、依賴項, 該鏡像為生産部署做了一些優化。
坑1:本次部署的是web app,不要使用【mcr.microsoft.com/dotnet/core/runtime:2.2】作為基礎鏡像,啟動容器會報錯:
It was not possible to find any compatible framework version
The specified framework 'Microsoft.AspNetCore.App', version '2.2.0' was not found.
-
Check application dependencies and target a framework version installed at:
/usr/share/dotnet/
- Installing .NET Core prerequisites might help resolve this problem: https://go.microsoft.com/fwlink/?LinkID=798306&clcid=0x409
- The .NET Core framework and SDK can be installed from: https://aka.ms/dotnet-download
因為該基礎鏡像不包含ASP.NET Core架構元件。
本次Dokefile的定義将會包含nginx,在容器内啟用Nginx标準配置代理請求到Kestrel:
6
7
8
9
10
11
12
13
14
15
16
17
18
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2
RUN apt-get update
RUN apt-get install -y nginx
WORKDIR /app
COPY bin/Debug/netcoreapp2.2/publish .
COPY ./startup.sh .
RUN chmod 755 /app/startup.sh
RUN rm /etc/nginx/nginx.conf
COPY nginx.conf /etc/nginx
ENV ASPNETCORE_URLS
http://+:5000EXPOSE 5000 80
CMD ["sh", "/app/startup.sh"]
Line 1 指定基礎鏡像
Line 3-4 從Debian package management store安裝Nginx
Line 6-7 設定工作目錄,放置ASP.NET Core WebApp部署包
Line 9-10 設定啟動腳本
Line 12-13 設定nginx配置檔案
Line 15-16 設定ASP.NETCore Kestrel在5000端口上監聽, 暴露5000,80 端口給容器外部
Line 18 稍後給出啟動腳本
tip: 需要了解容器内是一個獨立的linux環境,Dockfile中EXPOSE用于訓示容器打算暴露的端口。
這裡可隻暴露80端口給外部,但是必須給ASPNETCORE_URLS定義一個非80端口,作為容器内kestrel監聽端口。
最終(tree -L 1)輸出的app目錄結構如下
.
├── app.csproj
├── appsettings.Development.json
├── appsettings.json
├── bin
├── Dockerfile
├── nginx.conf
├── obj
├── Program.cs
├── Properties
├── Startup.cs
└── startup.sh
Nginx配置
建立以上Dockerfile中需要的nginx配置檔案,在同一目錄,vim nginx.conf 建立檔案:
19
20
21
22
23
24
worker_processes 4;
events { worker_connections 1024; }
http {
sendfile on;
upstream app_servers {
server 127.0.0.1:5000;
}
server {
listen 80;
location / {
proxy_pass http://app_servers;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
}
Line 8-10 定義一組伺服器(這裡隻有webapp), 資源名稱(app_servers)可用在本檔案任意位置。
Line 13 通知Nginx在80端口監聽
Line 15-22 訓示所有的請求都需要被代理到app_servers
總之,這個檔案定義了Nginx在80端口監聽外部請求,并将請求轉發給同一容器的5000端口。
啟動腳本
對于Docker容器,隻能使用一個CMD(或ENTRYPOINT定義),但是這種反向代理配置需要啟動Nginx和Kestrel, 是以我們定義一個腳本去完成這兩個任務
!/bin/bash
service nginx start
dotnet /app/app.dll
docker build -t example/hello-nginx .
該鏡像名稱為 example/hello-nginx 觀察輸出,會看到Dockerfile 中定義的每一步輸出。
該鏡像建構Dockerfile與vs docker tool生成的dockerfile進行對比,該檔案生成的鏡像更小,充分利用了鏡像分層的理念。
運作鏡像
docker run --name test -it -d -p 8080:80 example/test
該容器名稱為test, 現在可從
http://localhost:8080端口通路webapp, 通過curl -s -D - localhost:8080 -o /dev/null 驗證
通過shell終端進入容器内部, 可進一步分别探究Nginx和Kestrel服務:
docker exec -it test bash
curl -s -D - localhost:80 -o /dev/null
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Fri, 24 Feb 2017 14:45:03 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
curl -s -D - localhost:5000 -o /dev/null
Date: Fri, 24 Feb 2017 14:45:53 GMT
Server: Kestrel
tip:對于正在運作的容器,可使用docker exec -it [container_id] [command] 進入容器内部探究容器
對于啟動失敗的容器,可使用docker logs [container_id] 檢視容器輸出日志
了解一下docker的網絡基礎知識:
當Docker守護程序以其預設的配置參數在主控端啟動時,會建立一個名為docker0的Linux網橋裝置, 該網橋會自動配置設定滿足标準的私有IP段的随機IP直至和子網, 該子網決定了所有新建立容器将被配置設定的容器IP位址所屬網段。
可使用 docker inspect [container_id] 檢視network部配置設定置:
---- 截取自 docker inspect [container_id]的輸出---
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "a74331df40dc8c94483115256538304f1cbefe9f65034f20780a27271e6db606",
"EndpointID": "4f35ea62c1715bd9f6855bc82ada06e1bf5e58291dabb42e92ebc9552c6f017b",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
}
其中列出的NetworkID 正是 docker network ls 名為bridge的網橋, 這便是預設建立的docker0 網橋(docker inspect networkid 可繼續探究)。
正如上面所說,ASP.NET Core有兩種容器化反向代理部署架構,後續将會實踐以獨立容器分别部署Nginx、ASP.NET Core。
作者:Julian_醬