這算是比較特殊的情境,但因為現在的應用程式除了跨平台之外,程式本身有時候也會需要跨越使用。目前手上一個專案就是這樣的情況,使用 ASP.NET Core 2.1 開發,之後正式運作是要使用 docker 運行,而應用程式會在執行某項功能時去使用某個 NPM 來產出結果。
面對這樣的需求(這需求還是我自己想的)原本覺得應該不是什麼大問題,但就在第一步就遇到了狀況,而這篇文章就記錄幾個安裝的方式。
首先使用 VS2017 建立一個 ASP.NET Core 2.1 的 MVC 網站專案,這邊不勾選啟用 Docker 支援
建立 Dockerfile 並使用 Multi-Stage builds,這裡的內容其實與 VS2017 勾選 Docker 支援的所產生的 Dockerfile 差不多(我的這個 Dockerfile 檔案並不是放在 WebApplication1 專案目錄裡,而是放在 solution 目錄下)
Dockerfile
FROM microsoft/dotnet:2.1-sdk as builder WORKDIR /src COPY . . WORKDIR /src/WebApplication1 RUN dotnet restore RUN dotnet build --no-restore -c Release -o /app FROM builder as publish RUN dotnet publish --no-restore -c Release -o /app FROM microsoft/dotnet:2.1-aspnetcore-runtime WORKDIR /app COPY --from=publish /app . EXPOSE 80 ENTRYPOINT ["dotnet", "WebApplication1.dll"]
建立 docker-compose.yml 檔案(同樣的這個檔案也是放在 solution 目錄下)
version: "3.4" services: webapplication: image: webapplication build: context: . environment: - ASPNETCORE_ENVIRONMENT=Development ports: - "22816:80"
接著移到命令列裡執行 docker-compose build(這邊使用的是 cmder)
最後看到 Successfully 的訊息就表示已經把 WebApplication 的 docker image 建立完成
建置完成的 docker image 名稱為 webapplication 另外因為沒有特別指定標籤所以 Tag 為 latest,使用 Multi-Stage builds 建立 docker image 的過程會產生沒有名稱與沒有標籤的 image
使用以下指令進行移除
執行「docker-compose up –d」啟動 docker container
使用 portainer 的 Container console 功能進入 webapplication Container 裡,在 console 裡執行 npm –version 指令,可以看到因為沒有安裝 Node.js 所以執行結果所顯示的是 command not found
接著就讓我們在建立 webaplication 的 docker image 時安裝 Node.js
方式一
參考 aspnet/aspnet-docker/2.1 的說明
https://github.com/aspnet/aspnet-docker/tree/master/2.1
不過這邊會使用 Node.js Current Version: 10.8.0 (寫文章時的版本)
https://nodejs.org/en/download/current/
修改 Dockerfile,在最後一個 stage 裡增加安裝 Node.js 的指令。要注意 NODE_DOWNLOAD_SHA 要使用對映版本與檔案的值(https://nodejs.org/dist/v10.8.0/SHASUMS256.txt.asc)
執行 docker-compose build 指令建立 image ( 也可以使用 docker build )
在建立過程中就可以看到下載並且安裝的狀態
當 docker images 確認建立完成後執行 docker-compose up –d 啟動 webappliction 服務,然後使用 portanier 進入 webapplication container 的 console 裡,然後確認 Node.js 是否已安裝
方式二
這個解決方式是參考以下兩個連結的內容
https://stackoverflow.com/questions/45880460/enable-docker-support-for-angular-project
https://github.com/nodesource/distributions
Dockerfile
# Stage.1 FROM microsoft/dotnet:2.1-sdk as builder WORKDIR /src COPY . . WORKDIR /src/WebApplication1 RUN dotnet restore RUN dotnet build --no-restore -c Release -o /app # Stage.2 FROM builder as publish RUN dotnet publish --no-restore -c Release -o /app # Stage.3 FROM microsoft/dotnet:2.1-aspnetcore-runtime # Setup NodeJs RUN apt-get update && \ apt-get install -y wget && \ apt-get install -y gnupg2 && \ wget -qO- https://deb.nodesource.com/setup_10.x | bash - && \ apt-get install -y build-essential nodejs # End setup WORKDIR /app COPY --from=publish /app . EXPOSE 80 ENTRYPOINT ["dotnet", "WebApplication1.dll"]
從 deb.nodesource.com 取得安裝 Node.js 的 script 然後下載 Node.js 的 binary 檔案,然後使用 build-essential 進行編譯並安裝。
方式三
第三種方式則是直接從 Node.js 官網下載 source code
https://nodejs.org/download/release/v10.8.0/node-v10.8.0-linux-x64.tar.gz
Dockerfile
# Stage.1 FROM microsoft/dotnet:2.1-sdk as builder WORKDIR /src COPY . . WORKDIR /src/WebApplication1 RUN dotnet restore RUN dotnet build --no-restore -c Release -o /app # Stage.2 FROM builder as publish RUN dotnet publish --no-restore -c Release -o /app # Stage.3 FROM microsoft/dotnet:2.1-aspnetcore-runtime # install wget RUN apt-get update \ && apt-get install -y wget # install nodejs ENV NODE_VERSION 10.8.0 RUN wget https://nodejs.org/download/release/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz \ && tar -xzf "node-v${NODE_VERSION}-linux-x64.tar.gz" -C /usr/local --strip-components=1 \ && ln -s /usr/local/bin/node /usr/local/bin/nodejs \ && rm node-v${NODE_VERSION}-linux-x64.tar.gz WORKDIR /app COPY --from=publish /app . EXPOSE 80 ENTRYPOINT ["dotnet", "WebApplication1.dll"]
重新建置 docker image 之後並執行,然後確認 Node.js 是否安裝完成
方式四
有些開發環境的網路管制會比較嚴格,所以用上面三種在建立 docker image 時下載 Node.js 安裝就常常會出現錯誤,反而從開發者的電腦直接下載 Node.js 卻沒有問題(我目前的工作環境就是如此),所以就先下載 node-v10.8.0.tar.gz,然後在建立 docker image 的過程裡再將檔案複製過去並安裝。
Dockerfile
# Stage.1 FROM microsoft/dotnet:2.1-sdk as builder WORKDIR /src COPY . . WORKDIR /src/WebApplication1 RUN dotnet restore RUN dotnet build --no-restore -c Release -o /app # Stage.2 FROM builder as publish RUN dotnet publish --no-restore -c Release -o /app # Stage.3 FROM microsoft/dotnet:2.1-aspnetcore-runtime # install nodejs COPY ./nodejs . ENV NODE_VERSION 10.8.0 RUN tar -xzf "node-v${NODE_VERSION}-linux-x64.tar.gz" -C /usr/local --strip-components=1 \ && ln -s /usr/local/bin/node /usr/local/bin/nodejs \ && rm node-v${NODE_VERSION}-linux-x64.tar.gz WORKDIR /app COPY --from=publish /app . EXPOSE 80 ENTRYPOINT ["dotnet", "WebApplication1.dll"]
建置 docker image 之後並執行,然後確認 Node.js 是否安裝完成
將 Node.js 安裝完成後就會需要使用 npm 安裝一些 node package,安裝的操作指令同樣也可以寫在 Dockerfile 裡,不過網路管制比較嚴格的工作環境就會遇到很多很多的問題,因為眾多相依的 node packages 不一定會放在同樣的網站裡,大多數會放在 github 裡,但有時候放在 github 的檔案會轉址到 aws 上。當遇到因為網路限制而造成安裝 node packages 錯誤時,有些時候可以在 Dockerfile 裡設定 proxy 以及 npm config 設定 proxy,或許這麼做就可以解決,但絕大部分還是需要與網路管理的權責單位一同處理,看要將哪些來源網站設定為白名單裡,讓安裝問題可以解決。
之前我就是遇到這些問題,然後與系統管理部分的主管和同事一同來看要如何處理,不過絕大部分都是系統管理主管在分析與解決問題,畢竟 linux 環境與指令等我還是不太熟悉,也感謝有他們的協助讓我能夠完成這一道關卡,所以特別寫這篇文章做個記錄。
以上
沒有留言:
張貼留言