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應用
mkdir app
cd app
dotnet new web
dotnet restore
dotnet build

  以後將項目發佈到指定目錄(dotnet publish), 發佈產生的文件將會用於鏡像打包。html

 1. 編寫Dockerfile

  本次將以 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
 
由於該基礎鏡像是.NetCore 運行時鏡像,但不包含ASP.NET Core框架。
  
  本次Dokefile的定義將會包含nginx,在容器內啓用Nginx標準配置代理請求到Kestrel:
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://+:5000
EXPOSE 5000 80
 
CMD ["sh", "/app/startup.sh"]

  Line 1        指定基礎鏡像linux

  Line 3-4     從Debian package management store安裝Nginxnginx

  Line 6-7     設置工做目錄,放置ASP.NET Core WebApp部署包git

  Line 9-10   設置啓動腳本web

  Line 12-13 設置nginx配置文件docker

  Line 15-16 設置ASP.NETCore Kestrel在5000端口上監聽, 暴露5000,80 端口給容器外部shell

  Line 18 稍後給出啓動腳本json

tip: 須要理解容器內是一個獨立的linux環境,Dockfile中EXPOSE用於指示容器打算暴露的端口。 vim

        這裏可只暴露80端口給外部,可是必須給ASPNETCORE_URLS定義一個非80端口,做爲容器內kestrel監聽端口。bash

    最終(tree -L 1)輸出的app目錄結構以下

.
├── app.csproj
├── appsettings.Development.json
├── appsettings.json
├── bin
├── Dockerfile
├── nginx.conf
├── obj
├── Program.cs
├── Properties
├── Startup.cs
└── startup.sh

  

 2. 構建鏡像

  docker build -t example/hello-nginx .

  該鏡像名稱爲 example/hello-nginx  觀察輸出,會看到Dockerfile 中定義的每一步輸出。

  該鏡像構建Dockerfile與vs docker tool生成的dockerfile進行對比,該文件生成的鏡像更小,充分利用了鏡像分層的理念。

 

  Nginx配置

  建立以上Dockerfile中須要的nginx配置文件,在同一目錄,vim nginx.conf 建立文件:

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
  

 3. 運行鏡像

  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
HTTP/1.1 200 OK
Date: Fri, 24 Feb 2017 14:45:53 GMT
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Server: Kestrel

tip:對於正在運行的容器,可以使用docker exec -it  [container_id] [command]  進入容器內部探究容器

  對於啓動失敗的容器,可以使用docker logs [container_id]  查看容器輸出日誌
 
---------------------------------------------------------------------------------------------------- 華麗麗的分割線 --------------------------------------------------------------------------------------------
 
 瞭解一下docker的網絡基礎知識:

  當Docker守護進程以其默認的配置參數在宿主機啓動時,會建立一個名爲docker0的Linux網橋設備, 

       該網橋會自動分配RFC1918定義的私有IP段的隨機IP地址和子網, 該子網決定了全部新建立容器將被分配的容器IP地址所屬網段

docker network ls 列出全部網絡

  docker inspect [network_id]查看默認網絡的詳細信息,其中【Container】包含剛剛創建的容器 xenodochial_mahavira

[root@gs-server-5809 ~]$ docker  inspect a74331df40dc
[
    {
        "Name": "bridge",
        "Id": "a74331df40dc8c94483115256538304f1cbefe9f65034f20780a27271e6db606",
        "Created": "2018-12-28T17:05:33.100125947+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "3482bffb690c8a83c675ebd1d9bdcd149fc790ac8719bf447afae77e4cecbd7d": {
                "Name": "xenodochial_mahavira",
                "EndpointID": "1fe8569c3806b4b2bc032f54162a809ea3e18fd8e4ea41d68ed1a9e4f233eb17",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "510f41b1e39e983fbc7a75d235078d642c385f08a42e34bcfd5df14a07e3700c": {
                "Name": "gitlab-runner",
                "EndpointID": "ff9d8ac9ab9fbbf37be93f03bdc0fb3e7db803c1e0a5d0e0c533caf8de1cc0da",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

 

 上面顯示默認的容器都會加入名爲「bridge」的網絡,該網絡以bridge形式,利用的是docker0網橋設備,

可以使用 ip addr 確認系統已經存在 docker0網橋設備, 使用 brctl show 查看網橋鏈接哪些接口。

 

 

 正如上面所說,ASP.NET Core有兩種容器化反向代理部署架構,後續將會實踐以獨立容器分別部署Nginx、ASP.NET Core。 

做者: JulianHuang

碼甲拙見,若有問題請下方留言大膽斧正;碼字+Visio製圖,均爲原創,看官請不吝好評+關注,  ~。。~

本文歡迎轉載,請轉載頁面明顯位置註明原做者及原文連接

相關文章
相關標籤/搜索