docker部署ASP.NET Core、Nginx、MySQL


2019/10/24, docker 19.03.4, ASP.NET Core 3.0, CentOS 7.6

摘要:ASP.NET Core 3.0 網站項目容器化部署,使用docker-compose編排Nginx容器、MySQL容器、web容器
案例代碼

依賴結構介紹

整個網站項目取名samplems,一共需要三個容器(按依賴順序):
1.MySQL容器,取名為samplems.mysql,來自mysql(官方)鏡像
2.web容器,取名為samplems.web,來自samplemsweb(自己build出來的)鏡像
3.nginx容器,取名為samplems.nginx,來自nginx(官方)鏡像
使用docker-compose編排三個容器,建立橋接網絡(取名samplems-net)聯系三者

目錄結構

在CentOS7.6中/home/yzh(yzh是我登錄賬戶的個人文件夾)下新建deploy部署文件夾,用於存放部署所需文件,deploy里文件結構如下(后文會逐步建立以下內容):

│  docker-compose.yml       //compose編排文件
│ 
├─web                       //web 目錄 
│  │  Dockerfile            //web docker配置文件 
│  │                      
│  └─publish                //web 發布文件(發布生成的內容) 
│      ...                     
│      appsettings.json     //發布文件中包含appsettings.json,其中有數據庫連接配置 
│      ... 
│   
└─nginx                     //nginx目錄
    │                                                         
    └─confs                 //nginx 配置文件目錄
        nginx.conf          //nginx全局配置
        default.conf       //web項目對應的nginx配置文件

在vs中方案文件夾結構如下:

這樣組織后,WebApi發布到deploy/web/publish中,整個deploy文件夾打包發送到服務器進行部署。

把部署分為兩步:
1.構建所需鏡像
2.使用docker-compose編排容器

構建所需鏡像

MySQL鏡像

本次項目用到的MySQL鏡像直接使用官方鏡像,不需要進一步包裝修改,直接拉取(下載)官方鏡像:

docker pull mysql

MySQL配置數據庫密碼、數據卷掛載都稍后在docker-compose.yml中配置。

web鏡像

web項目准備

Visual Studio中,web項目的MySQL數據庫連接字符串(appsettings.json中)改為:

server=samplems.mysql;database=samplems;user=root;password=mysql@samplems

注意點:

  • server=samplems.mysql,這個地址就是我們的MySQL容器名;
  • 此處的密碼和后文中docker-compose.yml指定的MySQL密碼要一致;
  • 連接字符串沒有顯式指定連接端口,所以是默認的3306端口

web項目發布時,目標運行時選擇linux-x64可移植

將發布內容拷貝到目標系統上,把它放進/home/yzh/deploy/web/publish文件夾內,如下圖:

我這里web項目名稱為WebApi,所以其中的WebApi.dll就是后文Dockerfile中dotnet指令的對象。

Dockerfile編寫

/home/yzh/deploy/web文件夾下新建Dockerfile文件:

touch Dockerfile

內容如下:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.0
WORKDIR /app
COPY ./publish/ /app 
EXPOSE 80
ENTRYPOINT ["dotnet","WebApi.dll"]

上面五句話的意思分別是:

  • 基於mcr.microsoft.com/dotnet/core/aspnet:3.0鏡像(因為是netcore3.0的web項目),會自動下載該鏡像
  • 工作目錄為容器內的/app
  • 將/web/publish文件夾里所有內容拷貝至/app
  • 容器開放80端口
  • 使用dotnet運行asp.net core web項目,這里是"WebApi.dll",因為WebApi.dll就在工作目錄中,所以不需要任何路徑

構建web鏡像

在deploy/web文件夾下使用以下指令構建鏡像:(注意samplemsweb與.之間有空格,samplemsweb就是我們命名的鏡像名稱)

docker build -t samplemsweb .

如下圖所示:

Nginx鏡像

本次項目用到的Nginx鏡像直接使用官方鏡像,不需要進一步包裝修改,直接拉取(下載)官方鏡像:

docker pull nginx

Nginx配置

/home/yzh/deploy/nginx/confs/下新建nginx.conf文件,此文件是Nginx的配置文件,內容如下:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;


    #允許客戶端請求的最大字節
    client_max_body_size 256m;
    #緩沖區最大字節
    client_body_buffer_size 256k;

    #代理服務器鏈接后端服務器的超時時間
    proxy_connect_timeout 30;
    #代理服務器等待后端服務器響應的超時時間
    proxy_read_timeout 60;
    #后端服務器返回數據給代理服務器的最大傳輸時間
    proxy_send_timeout 30;
    #代理服務器緩沖區大小,客戶端的頭信息會保存在這里
    proxy_buffer_size 64k;
    #代理服務器有幾個緩沖區,最大是多大
    proxy_buffers 4 64k;
    #代理服務器繁忙可以申請更大的緩沖區,Nginx官方推薦為*2即可
    proxy_busy_buffers_size 128k;
    #代理服務器臨時文件大小
    proxy_temp_file_write_size 256k;

	#websocket 啟用
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

簡單解讀:

  • client_max_body_size 256m;是限制web上傳文件的大小限制
  • proxy開頭的配置是為了解決an upstream response is buffered to a temporary file報錯(請求文件大於緩沖區大小,導致寫入成臨時文件影響性能)
  • include /etc/nginx/conf.d/*.conf;是包含/etc/nginx/conf.d/下所有的配置文件,默認會有一個default.conf,下文會新建一個default.conf覆蓋默認的
  • 定義了nginx錯誤日志和訪問日志的路徑

/home/yzh/deploy/nginx/confs/下新建default.conf文件,內容如下:

#設定負載均衡后台服務器列表
upstream composeserver {
	#指定支持的調度算法
	ip_hash;
    server samplems.web:80;
}

#虛擬主機的配置
server {
    listen 80;
    location / {
        proxy_pass http://composeserver;
		
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	# 以下三句話是websocket啟用
	proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

注意點:

  • default.conf是nginx
  • 其中samplems.web就是我們web容器的名稱,后面的80即容器端口
  • listen 80 監聽80端口,也就是后文為什么要開放nginx容器的80端口

至此所有的鏡像已准備好

編寫docker-compose.yml

在deploy文件夾下新建docker-compose.yml文件,內容如下:

version: '3.4'

services:
  samplems.mysql:
    image: mysql
    container_name: samplems.mysql
    ports:
      - "3306:3306"
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=mysql@samplems
      - TZ=Asia/Shanghai
    volumes:
      - /app/data/mysql:/var/lib/mysql
    networks:
      - samplems-net

  samplems.web:
    image: samplemsweb
    container_name: samplems.web
    restart: always
    depends_on:
      - samplems.mysql
    environment:
      - TZ=Asia/Shanghai
    networks:
      - samplems-net


  samplems.nginx:
    image: nginx
    container_name: samplems.nginx
    restart: always
    ports:
      - "80:80"
      - "443:443"
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - /app/data/nginx/default.conf:/etc/nginx/conf.d/default.conf
      - /app/data/nginx/nginx.conf:/etc/nginx/nginx.conf
      - /app/logs/nginxlogs:/var/log/nginx
    depends_on:
      - samplems.web
    networks:
      - samplems-net

networks:
  samplems-net:
    driver: bridge

如上代碼所示,整個yml文件結構大致分為version、services、networks三塊,其中services內又有samplems.mysql、samplems.web、samplems.nginx三塊

samplems.mysql:

  • image 表示引用的鏡像,這里是官方的mysql
  • container_name:容器名稱(其他兩個容器這個字段的定義類似)
  • ports 映射的端口號,宿主機的3306映射到容器的3306端口(其他兩個容器這個字段的定義類似)
  • restart: always 指定容器退出后的重啟策略為始終重啟(其他兩個容器這個字段的定義相同)
  • environment 中定義了MySQL root賬號的密碼為mysql@samplems,這里需要和web項目中密碼保持一致
  • environment 中定義了容器時區為亞洲上海,防止容器時區和宿主機時區不一致導致獲取到的時間有偏差(其他兩個容器這個字段的定義相同)
  • volumes 掛載數據卷,將容器中所有要寫入/var/lib/mysql中的數據庫文件,寫入到宿主機/app/data/mysql中(這樣即使mysql容器被刪除,數據依然存在)
  • networks 使用自定義的samplems-net橋接網絡(其他兩個容器這個字段的定義相同)

samplems.web:

  • image 這里引用的是我們自己build的web鏡像
  • depends_on 表明容器要先啟動samplems.mysql,再啟動samplems.web

samplems.nginx:

  • ports 80端口是默認的http端口,443是默認的https端口
  • volumes 掛載數據卷,將default.conf和nginx.conf兩個配置文件映射到容器中,這樣如果配置文件變動不需要重新構建nginx鏡像(可以看到兩個文件都在/app/data/nginx/下,所有容器編排啟動前,需要將配置文件拷貝到/app/data/nginx/下)
  • volumes 掛載數據卷,將容器中所有要寫入/var/log/nginx中的文件,寫入到宿主機/app/logs/nginxlogs中,這里主要是nginx的日志文件
  • depends_on 表明容器要先啟動samplems.web,再啟動samplems.nginx,如此一來,啟動的先后順序為 mysql->web->nginx

啟動容器

啟動容器前,需要將nginx的配置文件拷貝至/app/data/nginx/下

#創建目錄
sudo mkdir -p /app/data
#復制文件{/home/yzh}請對應修改
sudo cp -rf /home/yzh/deploy/nginx/confs /app/data/nginx

至此所有的准備工作都已完成,在deploy文件夾下執行以下命令啟動容器:

docker-compose up -d

如下圖,三個綠色的done表示三個容器啟動成功:

使用docker ps查看容器的運行狀態,是正常運行:

開放宿主機防火牆80端口:

sudo firewall-cmd --zone=public --add-port=80/tcp --permanent
sudo systemctl restart firewalld

瀏覽器訪問CentOS的IP地址,即可查看網頁:

注意點:

1.Linux下使用到的腳本、配置文件,在visual studio中建議使用高級保存選項:utf-8編碼、Unix換行格式進行保存(如果這樣還報錯,可以直接在Linux下新建文件,再把內容復制進去)

2.網站Program.cs中,建議把CreateHostBuilder(args).Build().Run()包裹在try catch中,這樣網站出錯后容器會自動重啟

整個訪問流程

流程:
1.瀏覽器訪問CentOS的IP地址(默認80端口)時,訪問到宿主機的80端口
2.由於docker-compose.yml中定義了nginx的端口80:80,所有宿主機的80端口映射到nginx容器的80端口
3.由於nginx容器的配置文件default.conf定義了監聽80端口,所以能響應到瀏覽器的請求
4.由於nginx容器的配置文件default.conf定義了反向代理,將請求轉發給了samplems.web容器(因為共用了samplems-net網絡,所以能找到對方),端口也是80
5.samplems.web在Dockerfile中暴露了80端口,所以響應nginx的轉發,web服務做出對應response返回數據內容
6.因為共用了samplems-net網絡,所以web服務在連接數據庫中,能找到samplems.mysql,應用了數據庫操作


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM