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 環境與指令等我還是不太熟悉,也感謝有他們的協助讓我能夠完成這一道關卡,所以特別寫這篇文章做個記錄。


以上

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。