網頁

2018年8月7日 星期二

在 ASP.NET Core 2.1 的 docker image 裡安裝 Node.js

這算是比較特殊的情境,但因為現在的應用程式除了跨平台之外,程式本身有時候也會需要跨越使用。目前手上一個專案就是這樣的情況,使用 ASP.NET Core 2.1 開發,之後正式運作是要使用 docker 運行,而應用程式會在執行某項功能時去使用某個 NPM 來產出結果。

面對這樣的需求(這需求還是我自己想的)原本覺得應該不是什麼大問題,但就在第一步就遇到了狀況,而這篇文章就記錄幾個安裝的方式。


首先使用 VS2017 建立一個 ASP.NET Core 2.1 的 MVC 網站專案,這邊不勾選啟用 Docker 支援

image

建立 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)

image

最後看到 Successfully 的訊息就表示已經把 WebApplication 的 docker image 建立完成

image

建置完成的 docker image 名稱為 webapplication 另外因為沒有特別指定標籤所以 Tag 為 latest,使用 Multi-Stage builds 建立 docker image 的過程會產生沒有名稱與沒有標籤的 image

image

使用以下指令進行移除

image

執行「docker-compose up –d」啟動 docker container

image

使用 portainer 的 Container console 功能進入 webapplication Container 裡,在 console 裡執行 npm –version 指令,可以看到因為沒有安裝 Node.js 所以執行結果所顯示的是 command not found

image

接著就讓我們在建立 webaplication 的 docker image 時安裝 Node.js


方式一

參考 aspnet/aspnet-docker/2.1 的說明
https://github.com/aspnet/aspnet-docker/tree/master/2.1

image

不過這邊會使用 Node.js Current Version: 10.8.0 (寫文章時的版本)
https://nodejs.org/en/download/current/

image

修改 Dockerfile,在最後一個 stage 裡增加安裝 Node.js 的指令。要注意 NODE_DOWNLOAD_SHA 要使用對映版本與檔案的值(https://nodejs.org/dist/v10.8.0/SHASUMS256.txt.asc

image

執行 docker-compose build 指令建立 image ( 也可以使用 docker build )

在建立過程中就可以看到下載並且安裝的狀態

image

當 docker images 確認建立完成後執行 docker-compose up –d 啟動 webappliction 服務,然後使用 portanier 進入 webapplication container 的 console 裡,然後確認 Node.js 是否已安裝

image


方式二

這個解決方式是參考以下兩個連結的內容
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

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 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 是否安裝完成

image


方式四

有些開發環境的網路管制會比較嚴格,所以用上面三種在建立 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"]

image

建置 docker image 之後並執行,然後確認 Node.js 是否安裝完成

image



將 Node.js 安裝完成後就會需要使用 npm 安裝一些 node package,安裝的操作指令同樣也可以寫在 Dockerfile 裡,不過網路管制比較嚴格的工作環境就會遇到很多很多的問題,因為眾多相依的 node packages 不一定會放在同樣的網站裡,大多數會放在 github 裡,但有時候放在 github 的檔案會轉址到 aws 上。當遇到因為網路限制而造成安裝 node packages 錯誤時,有些時候可以在 Dockerfile 裡設定 proxy 以及 npm config 設定 proxy,或許這麼做就可以解決,但絕大部分還是需要與網路管理的權責單位一同處理,看要將哪些來源網站設定為白名單裡,讓安裝問題可以解決。

之前我就是遇到這些問題,然後與系統管理部分的主管和同事一同來看要如何處理,不過絕大部分都是系統管理主管在分析與解決問題,畢竟 linux 環境與指令等我還是不太熟悉,也感謝有他們的協助讓我能夠完成這一道關卡,所以特別寫這篇文章做個記錄。


以上

沒有留言:

張貼留言