開(kāi)發(fā)環(huán)境:桌面云系統(tǒng)(無(wú)法使用docker desktop),win10系統(tǒng)
后端開(kāi)發(fā)工具:vs2022 數(shù)據(jù)庫(kù):mysql 緩存:redis 隊(duì)列和事件處理:rabbitmq
前端開(kāi)發(fā)工具:visual studio code 框架:vue
發(fā)布步驟
一、發(fā)布接口端.NET6 項(xiàng)目
1. 由于不能運(yùn)行docker desktop,所以發(fā)布的時(shí)候只能發(fā)布到文件夾,然后手動(dòng)發(fā)布到docker,發(fā)布界面如下,注意下圖紅框選中處,這就是我踩的第一個(gè)坑,發(fā)布時(shí)我想著是發(fā)布到liunx系統(tǒng),所以選擇的是liunx-64,發(fā)布后才發(fā)現(xiàn)運(yùn)行不了,報(bào)錯(cuò)內(nèi)容為:
System.InvalidOperationException: Unable to resolve service for type '***.***.***' while attempting to activate '***.***.***'
錯(cuò)誤意思就是加載dll文件失敗,后面將目標(biāo)運(yùn)行時(shí)改為 可移植 然后重新發(fā)布,更新后,重新運(yùn)行dcoker(docker restart 容器Id),問(wèn)題解決

2. dockerfile文件編寫(xiě),dockerfile文件可以由系統(tǒng)自動(dòng)生成,但是手動(dòng)發(fā)布需要修改系統(tǒng)生成的dockerfile文件,因?yàn)槭謩?dòng)發(fā)布已經(jīng)生成了dll文件,不需要調(diào)用build命令再次生成
下面是系統(tǒng)生成的dockerfile,包括了復(fù)制項(xiàng)目文件到對(duì)應(yīng)文件夾和build生成dll文件
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src COPY ["WebApi/Web/Web.csproj", "WebApi/Web/"] COPY ["WebApi/AdminApi/AdminApi.csproj", "WebApi/AdminApi/"] RUN dotnet restore "WebApi/Web/Web.csproj" COPY . . WORKDIR "/src/WebApi/Web" RUN dotnet build "Web.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "Web.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "Web.dll"]
下面是我修改后的dockerfile文件,內(nèi)容簡(jiǎn)潔很多,只保留了程序入口以及運(yùn)行端口指定
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443
#拷貝發(fā)布目錄下的所有文件到容器的工作根目錄,如果你的站點(diǎn)文件和dockerfile在同一個(gè)文件夾下面可以和下面一樣否則要加上站點(diǎn)文件的目錄
COPY ./ ./
#COPY fonts/ /usr/share/fonts/
ENV ASPNETCORE_ENVIRONMENT Development # 設(shè)置運(yùn)行環(huán)境為開(kāi)發(fā)環(huán)境,可選值為 Production、Development、Staging 默認(rèn)值為Production
ENTRYPOINT ["dotnet", "Web.dll"]
3. 將文件上傳至centos系統(tǒng),可用的工具有很多,我這邊使用的工具是FinalShell,該工具支持界面操作,比其它工具操作要簡(jiǎn)單一些,比如修改配置文件可以在本地打開(kāi),然后直接修改保存,不需要在命令行里面云操作,同時(shí)也可以直接拖動(dòng)文件到指定目錄
4. 創(chuàng)建鏡像文件,文件上傳后,進(jìn)行文件所在目錄,cd 文件目錄 。然后使用以下命令 創(chuàng)建鏡像文件 注意后面的 . 不能少
docker build -t 鏡像名稱(chēng):版本號(hào) .
5. 啟動(dòng)運(yùn)行容器 ,使用下面的命令啟動(dòng)容器 其中8001是系統(tǒng)的端口號(hào),80是容器 --restart=always 表示容器停止后自動(dòng)重啟(比如服務(wù)器重啟了),如果運(yùn)行容器時(shí)沒(méi)有加這個(gè)參數(shù),可以使用docker container update --restart=always 容器名字 來(lái)修改, -e TZ=Asia/Shanghai 表示指定容器的時(shí)區(qū),以免.net core獲取的時(shí)間不正確 -v 是指定掛載目錄/home/OnlineBusiness/dotnet_docker_test宿主機(jī)目錄,--log-opt 是docker的日志生成參數(shù) max-size=100m,是限制日志文件大小為100M max-file=10是指最多保留10個(gè)日志文件,超過(guò)的將刪除 :后面的是docker應(yīng)用內(nèi)目錄
docker run -d -p 8030:80 --name 容器名稱(chēng) --restart=always -e TZ=Asia/Shanghai -d -v /home/OnlineBusiness/dotnet_docker_test:/app --log-opt max-size=100m --log-opt max-file=10 鏡像名稱(chēng):版本號(hào)
6. 如果容器啟動(dòng)成功,可以使用docker ps查看運(yùn)行中的容器,這時(shí)使用 服務(wù)器IP:端口號(hào) 及可訪(fǎng)問(wèn)系統(tǒng),系統(tǒng)部署完成
7. docker日志目錄 /var/lib/docker/containers/容器ID/容器ID-json.log
8. 踩到的坑
坑一:上面已經(jīng)說(shuō)了,發(fā)布時(shí)選擇目標(biāo)運(yùn)行時(shí)的問(wèn)題,我這里改成可移植即可運(yùn)行
坑二:swagger運(yùn)行不了,linux系統(tǒng)目錄的問(wèn)題導(dǎo)致swagger運(yùn)行不了,根據(jù)錯(cuò)誤信息查了一下是因?yàn)槁窂降膯?wèn)題,加載xml文件失敗,導(dǎo)致swagger運(yùn)行失敗,liunx系統(tǒng)里面的路徑要注意兩點(diǎn),1) 目錄的分隔符與windows不一致,建議拼接路徑是使用Path.DirectorySeparatorChar來(lái)獲取分隔符,這樣就不需要判斷運(yùn)行環(huán)境了,我這里swagger運(yùn)行不了就是因?yàn)槭褂脀indows里面的目錄分隔符。 2)獲取當(dāng)前目錄,建議使用Directory.GetCurrentDirectory(),不要使用AppContext.BaseDirectory,這個(gè)方法在開(kāi)發(fā)環(huán)境中獲取到的是.dll文件所有目錄
坑三:ZKWeb.System.Drawing組件的使用,在liunx里面使用該 組件需要另外安裝該組件,關(guān)鍵是我安裝了也解決不了問(wèn)題,解決方案見(jiàn)另外一篇博文http://www.rzrgm.cn/ithome8/p/16423027.html,這里不再說(shuō)明。
坑四:rabbitmq的使用,當(dāng)然這個(gè)和發(fā)布沒(méi)有多大關(guān)系,是因?yàn)榘l(fā)布的站點(diǎn)和本地站點(diǎn) 使用同一個(gè)rabbitmq服務(wù)器時(shí)會(huì)報(bào)錯(cuò),沖突了,訪(fǎng)問(wèn)同一隊(duì)列,不使用同一個(gè)服務(wù)器就OK了。
二、發(fā)布前端VUE項(xiàng)目
1. 進(jìn)入CMD模式,并且進(jìn)入項(xiàng)目的根目錄 ,使用npm run build進(jìn)行項(xiàng)目打包,也可以使用VSCode,在終端下面輸入npm run build來(lái)進(jìn)行打包,命令執(zhí)行后文件會(huì)打包到vue.config.js文件中配置的outputdir指定的目錄下面。
2. 編寫(xiě)nginx config配置文件,內(nèi)容如下,在項(xiàng)目發(fā)布的目錄下面創(chuàng)建nginx/conf.d目錄,將該文件保存到該 目錄并且命名為default.conf,注意最好不要在中使用中文,否則可能會(huì)亂碼
server { listen 80; listen [::]:80; server_name localhost; # 測(cè)試vue history 模式下發(fā)布問(wèn)題 # 方式一 一般選用方式二就可以 location / { root /usr/share/nginx/html; index index.html index.htm; client_max_body_size 200m; if (!-e $request_filename) { rewrite ^/(.*) /index.html last; break; } error_page 404 /404.html; # To allow POST on static pages error_page 405 =200 $uri; } # 此外,如果VUE應(yīng)用沒(méi)有發(fā)布在域名的目錄根下,比如[http://xxx.com/wx/] # 那么除了上述配置: #location /wx{ # root /data/nginx/html; # 在linux下部署一般都是將路徑配置完全 #root html; #index index.html index.htm; #error_page 404 /wx/index.html; #if (!-e $request_filename) { #rewrite ^/(.*) /wx/index.html last; #break; #} #} # 方式二 #location / { #try_files $uri $uri/ /index.html; #} # 配置反響代理接口的反響代理,這里是反向代理的接口配置,不然會(huì)訪(fǎng)問(wèn)不了接口 location ~ /admin/ { proxy_set_header Host $http_host; proxy_set_header X-Real-Ip $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #//利用正則進(jìn)行匹配#去掉api前綴,$1是正則中的第一串,這樣后端的接口也不需要帶api了 rewrite ^/(.*)$ /$1 break; #**//api前面的部分將被替換成localserver的地址** proxy_pass http://172.16.19.155:8030; } # 配置反響代理接口的反響代理 location ~ /WebApi/ { proxy_set_header Host $http_host; proxy_set_header X-Real-Ip $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #//利用正則進(jìn)行匹配#去掉api前綴,$1是正則中的第一串,這樣后端的接口也不需要帶api了 rewrite ^/(.*)$ /$1 break; #**//api前面的部分將被替換成localserver的地址** proxy_pass http://172.16.19.155:8030; } #access_log /var/log/nginx/host.access.log main; }
3. 編寫(xiě)dockerfile文件,內(nèi)容如下 ,也可以直接將文件上傳到指定目錄,后面的COPY命令就可以不用了
# 設(shè)置基礎(chǔ)鏡像 FROM nginx # 將dist文件中的內(nèi)容復(fù)制到 ./html/ 這個(gè)目錄下面,./html/是nginx容器的默認(rèn)文件目錄 COPY dist/ ./html/ # 用本地的 default.conf 配置來(lái)替換nginx鏡像里的默認(rèn)配置,確認(rèn)文件的路徑是正確的 ADD conf.d/default.conf /etc/nginx/conf.d/
4. 創(chuàng)建鏡像文件,文件上傳后,進(jìn)行文件所在目錄,cd 文件目錄 。然后使用以下命令創(chuàng)建鏡像文件 ,注意后面的 . 不能少
docker build -t 鏡像名稱(chēng):版本號(hào) .
5. 啟動(dòng)運(yùn)行容器 ,使用以下代碼 其中8001是系統(tǒng)的端口號(hào),80是容器的端口號(hào),如果要打開(kāi)就是系統(tǒng)的 IP:8002
docker run --name=容器名稱(chēng) -p 8002:80 -d 鏡像名稱(chēng):版本號(hào)
6. 至此VUE項(xiàng)目發(fā)布就完成了,下面說(shuō)一下踩的坑
坑一:發(fā)布后打開(kāi)網(wǎng)站是一片空白,只有兩個(gè)JS報(bào)錯(cuò),通過(guò)查詢(xún)知道了是什么原因,是配置文件vue.config.js里面沒(méi)有指定publicPath,導(dǎo)致vue找不到目錄,加上即可,代碼如下
const urlConfig = require('./src/config/url') // 引入服務(wù)器路徑配置 const path = require('path') const resolve = (dir) => path.join(__dirname, dir) module.exports = { // 部署應(yīng)用包時(shí)的基本 URL publicPath: process.env.NODE_ENV === 'production' ? '/admin' : '/', // 當(dāng)運(yùn)行 vue-cli-service build 時(shí)生成的生產(chǎn)環(huán)境構(gòu)建文件的目錄 outputDir: '../../publish/dist', // 放置生成的靜態(tài)資源 (js、css、img、fonts) 的 (相對(duì)于 outputDir 的) 目錄 assetsDir: 'static', publicPath: './',
坑二:接口調(diào)用報(bào)跨域錯(cuò)誤,獲取不到數(shù)據(jù),在本地開(kāi)發(fā)正常,是因?yàn)殚_(kāi)發(fā)環(huán)境是使用的proxy做了代理轉(zhuǎn)發(fā),所以可以正常訪(fǎng)問(wèn),下面這段代碼會(huì)進(jìn)行轉(zhuǎn)發(fā),所以在開(kāi)發(fā)環(huán)境可以正常訪(fǎng)問(wèn)不會(huì)跨域
devServer: { open: false, host: '0.0.0.0', port: 8031, https: false, hotOnly: false, proxy: { '/admin': { target: urlConfig.proxyURL, ws: false, secure: false, changeOrigin: true } }, before: () => { } }
解決方案,代碼里面接口的訪(fǎng)問(wèn)地址仍然使用項(xiàng)目的訪(fǎng)問(wèn)地址,在nginx里面做配置,進(jìn)行反向代理,跳轉(zhuǎn)到接口的地址,配置代碼如下
# 配置反響代理接口的反響代理,這里是反向代理的接口配置,不然會(huì)訪(fǎng)問(wèn)不了接口 location ~ /admin/ { proxy_set_header Host $http_host; proxy_set_header X-Real-Ip $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #//利用正則進(jìn)行匹配#去掉api前綴,$1是正則中的第一串,這樣后端的接口也不需要帶api了 rewrite ^/(.*)$ /$1 break; #**//api前面的部分將被替換成localserver的地址** proxy_pass http://***.***.***.***:8001; }
在此記錄一下,以免后面還遇到這些問(wèn)題。。。
浙公網(wǎng)安備 33010602011771號(hào)