在開發階段可即時測試 Linux 環境

雖然可以在 Windows 或 macOS 開發 .NET Core,但畢竟 production 環境是 Linux,因此在 Windows 或 macOS 測試成功,也不代表真正上 Linux 沒有問題。

透過 Docker,我們可以在開發階段就測試 Linux 環境,及早發現可能的問題。

Version


macOS High Sierra 10.13.4
Docker for Mac 18.03-ce-mac65 (24312)
.NET Core 2.0.7
VS Code 1.23.1

建立 .NET Core App


1
$ dotnet new console -o MyConsole

使用 dotnet new 建立 .NET Core App。

  • new : 建立 project
  • console : 建立 console 類型 project
  • -o : 以 MyConsole 為專案名稱並建立目錄

DockerDev004

執行 .NET Core App


1
2
$ cd MyConsole
~/MyConsole $ dotnet run

進入 MyConsole 目錄,並在 Host OS 執行 .NET Core App。

DockerDev005

目前 .NET Core App 是跑在 Host OS,也就是 macOS,但並不保證在 Linux 也正常,因此我們必須進一步在 Linux 環境下測試。

實務上有兩種測試方式:

  • 在 Container 內測試
  • 在 Container 外測試

在 Container 內測試


我們先將 container 執行起來,然後連進 container 內部,以 Linux 環境執行 app。

建立 Docker Compose

docker-compose.yml

1
version: "3"

services:
  net-core:
    image: microsoft/dotnet
    container_name: MyCore
    volumes:
      - "${HOST_DIR}:/home/"
    tty: true

第 5 行

1
image: microsoft/dotnet

其基底的 image 為 microsoft/dotnet,此為 Micrsoft 所發布的 official .NET Core docker image。

實務上 Docker 建議盡量使用 official image,避免被安裝木馬程式而不自知

第 6 行

1
container_name: MyCore

建立名為 MyCore 的 container。

container_name 相當於 docker run--name

第 7 行

1
volumes:
  - "${HOST_DIR}:/home/"

設定 Host OS 與 container 所共享的目錄,將來 Host OS 所分享的目錄,相當於 container 內的 /home 目錄。

由於每個人 Host OS 要分享的目錄都不一樣,因此設定成 HOST_DIR 變數,稍後自行在 .env 設定。

volumns 相當於 docker run-v

第 9 行

1
tty: true

Docker 為了節省硬體資源,app 執行完就會釋放 container,但處於開發階段,我們需要的是類似 service 跑在背景,隨時可以進入 container 測試 Linux app。

tty: true 將令 Docker 分配一個 TTY (T ele TY pewriter),綁定到 container 的 stdinstdout 上,將來我們才能透過 Bash 對 container 下指令,由於 tty 在背景持續執行,因此 container 就不會被釋放。

tty 相當於 docker run-t

DockerDev000

.env

1
HOST_DIR=~/Code/CSharp/MyConsole

設定 Host OS 要與 container 共享的目錄。

注意 = 前後都沒有空格,否則 docker-compose 會執行錯誤。

設計 docker-compose.yml 時,要盡量保持 .yml 不要修改,也就是 開放封閉原則,而將要修改客製化的部分搬到 .env,將來 docker-compose.yml 會進 git,但 .env 則不進 git

DockerDev001

執行 Docker Compose

1
$ docker-compose up -d

進入 docker-compose.yml 所在的目錄,執行 docker-compose up 執行 container。

  • -dd etatch,表示 docker-compose 執行後將離開 container 的 process,讓 container 在背景執行

DockerDev002

1
$ docker ps

可以發現 MyCore container 正在背景執行中,沒有被釋放。

DockerDev003

連進 Container 內

1
2
3
~/MyConsole $ docker exec -it MyCore bash
root@83aeee036235:/# cd /home/
root@83aeee036235:/home# dotnet run

使用 docker exec -it MyCore bash 進入 container。

  • exec:執行 container 內的 Linux 指令
  • -ii nteractive,可對 terminal 輸入資料
  • -tt erminal,可對 terminal 顯示資料
  • MyCore:container 名稱
  • bash:在 container 執行 bash,讓我們可以對 Linux 下指令

進入 /home,此為剛剛我們在 .env 所設定的共享目錄。

使用 dotnet run 執行 .NET Core App。

DockerDev006

目前是同一份 code 真正跑在 Linux,因此可藉由 Docker 在開發階段,測試 app 是否真正能跑在 Linux。

結束 Docker Compose

1
$ docker-compose down

進入 docker-compose.yml 所在的目錄,執行 docker-compose down 結束 container。

DockerDev007

1
$ docker ps

Container 已經結束且被釋放。

DockerDev008

1
$ docker ps -a

Container 不僅被釋放,且在硬碟的 container 也被刪除了。

若使用 docker run,儘管使用 docker stop 停止 container,但 container 仍然存在於硬碟,必須手動使用 docker rm 刪除 container,但若使用 docker-compose down,會一併從硬碟刪除 container

DockerDev009

在 Container 外測試


直接在 container 外部使用 docker run 執行 container,並在 container 內執行 dotnet run

建立 Bash

RunDocker.sh

1
2
3
4
#!/bin/bash
HOST_DIR=~/Code/CSharp/MyConsole

docker run --rm -v $HOST_DIR:/home -w /home microsoft/dotnet dotnet run

第 2 行

1
HOST_DIR=~/Code/CSharp/MyConsole

設定 Host OS 與 container 所共享的目錄,將來 Host OS 所分享的目錄,相當於 container 內的 /home 目錄。

由於每個人 Host OS 要分享的目錄都不一樣,因此設定成 HOST_DIR 變數,可自行設定。

第 4 行

1
docker run --rm -v $HOST_DIR:/home -w /home microsoft/dotnet dotnet run

使用 docker run 直接執行 container。

  • –rm:執行完 app 之後立即刪除 container,避免執行完的 container 留在硬碟內,除了佔空間,日後還必須手動刪除
  • -vv olumn,設定 Host OS 與 container 所共享的目錄,: 左側為 Host OS 目錄,右側為 container 內目錄
  • -ww orking directory,避免自己下 cd 指令切換目錄
  • microsoft/dotnet:Microsoft 官方最新的 .NET Core Docker image
  • dotnet run:container 建立後,要在 container 內執行的指令就是 dotnet run

DockerDev010

設定執行權限

1
~MyConsole $ chmod +x RunDocker.sh

使用 chmodRunDocker.sh 能夠有 被執行 權限。

DockerDev011

執行 Bash

1
~/MyConsole $ ./RunDocker.sh

執行 RunDocker.sh ,建立 container,並在 container 內執行 app。

DockerDev012

目前是同一份 code 在 Docker 內執行,由於 Docker 內就是 Linux,因此可藉由 Docker 在開發階段,測試 app 是否真正能跑在 Linux。

Conclusion


  • .NET Core 雖然號稱跨平台,但也不保證真正執行在 Linux 沒問題,透過 Docker,我們在開發階段就能很簡單測試 Linux 環境是否正常
  • 第一種方式比較接近傳統 VM,直接進 container 內測試 app
  • 第二種方式比較接近正統 Docker,是直接使用 docker run 執行 container 內的 app
  • 以上兩種方式都只適合開發階段測試用,若要上 production,則要將 .NET Core App 整個包進 Docker image,將以專文另外討論之

Sample Code


完整的範例可以在我的 GitHub 上找到

2018-05-30