.NET Core容器化@Docker

舒適提示:本文略長,預計讀完本文需耗時8mins。若要一步一步跟隨實操演練,預計耗時30mins,請泡上一杯咖啡,找個安靜的角落,打開電腦動手演練,效果更佳。 html

# 1. 引言 咱們知道. NET Core最大的特性之一就是跨平臺,而對於跨平臺,彷佛你們印象中就是能夠在非Windows系統上部署運行。而至於如何操做,可能就有所欠缺。那這一節咱們就結合簡單實例一步一步教你如何藉助Docker來容器化 .NET Core應用,以完成跨平臺的構建和部署。linux

# 2. 環境準備 自從玩.NET就一直和Windows系統打交道,若是還基於Windows來展開本節內容,不就跑題了嗎?!那我們就切換到Linux系統。 若是沒有Linux基礎和Docker基礎,請自覺完成如下兩個實驗: 騰訊雲開發者實驗室:Linux 基礎入門 騰訊雲開發者實驗室:搭建 Docker 環境git

完成了以上兩個實驗後,咱們就離Linux的世界更近一步。 由於後續是基於Linux-CentOS系統進行實操演練,沒有Linux上機環境的,能夠考慮從騰訊雲實驗室列表找一個CentOS相關的實驗項目做爲本文的演練環境。web

# 3. Docker簡介 在開始以前,有必要對Docker作一下簡單瞭解,能夠參考個人上一篇文章Hello Docker。 這裏就簡要的再重複一下。 Docker是用Go語言編寫基於Linux操做系統的一些特性開發的,其提供了操做系統級別的抽象,是一種容器管理技術,它隔離了應用程序對基礎架構(操做系統等)的依賴。相較於虛擬機而言,Docker共享的是宿主機的硬件資源,使用容器來提供獨立的運行環境來運行應用。虛擬機則是基於Supervisor(虛擬機管理程序)使用虛擬化技術來提供隔離的虛擬機,在虛擬機的操做系統上提供運行環境!雖然二者都提供了很好的資源隔離,但很明顯Docker的虛擬化開銷更低! Docker涉及了三個核心概念:Register、Image、Container。docker

1. Registry:倉庫。用來存儲Docker鏡像,好比Docker官方的Docker Hub就是一個公開的倉庫,在上面咱們能夠下載咱們須要的鏡像。 2. Image:鏡像。開發人員建立一個應用程序或服務,並將它及其依賴關係打包到一個容器鏡像中。鏡像是應用程序的配置及其依賴關係的靜態形式。 3. Container:容器。Container是鏡像的運行實例,它是一個隔離的、資源受控的可移植的運行時環境,其中包含操做系統、須要運行的程序、運行程序的相關依賴、環境變量等。json

它們三者的相互做用關係是: 當咱們執行Docker pull或Docker run命令時,若本地無所需的鏡像,那麼將會從倉庫(通常爲DockerHub)下載(pull)一個鏡像。Docker執行run方法獲得一個容器,用戶在容器裏執行各類操做。Docker執行commit方法將一個容器轉化爲鏡像。Docker利用login、push等命令將本地鏡像推送(push)到倉庫。其餘機器或服務器上就可使用該鏡像去生成容器,進而運行相應的應用程序。ubuntu

4. 安裝Docker

4.1. 使用腳本自動安裝Docker

在測試或開發環境中 Docker 官方爲了簡化安裝流程,提供了一套便捷的安裝腳本,CentOS系統上可使用這套腳本安裝:瀏覽器

//使用腳本自動化安裝Docker
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
複製代碼

4.2. 啓動Docker

執行這個命令後,腳本就會自動的將一切準備工做作好,而且把 Docker CE 的 Edge 版本安裝在系統中。bash

//啓動 Docker CE
$ sudo systemctl enable docker
$ sudo systemctl start docker
//查看docker版本
$ sudo docker -v
Docker version 1.12.6, build ec8512b/1.12.6
複製代碼

4.3 測試Docker是否正確安裝

命令行執行docker run hello-world服務器

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete
Digest: sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://cloud.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
複製代碼

當執行docker run hello-world時,docker首先會從本地找hello-world的鏡像,若是本地沒有,它將會從默認的鏡像倉庫Docker Hub上拉取鏡像。鏡像拉取到本地後,就實例化鏡像獲得容器,輸出Hello from Docker!

4.4. 配置鏡像加速

由於默認的鏡像倉庫遠在國外,拉取一個小的鏡像時間還能夠忍受,若拉取一個上G的鏡像就有點太折磨人了,咱們使用DaoCloud鏡像加速器來進行鏡像加速。Linux上配置方法以下:

$ curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://37bb3af1.m.daocloud.io`
$ sudo systemctl restart docker
複製代碼

5. Hello Docker With .NET Core

Docker安裝完畢,咱們來結合.NET Core玩一玩吧。

5.1. 拉取microsoft/dotnet鏡像

命令行執行docker pull microsoft/dotnet,等幾分鐘後便可安裝完畢,執行docker images能夠看到本地已經包含microsoft/dotnetdocker.io/hello-world兩個鏡像。

5.2. 運行microsoft/dotnet鏡像

使用docker run <image>能夠啓動鏡像,經過指定參數-it以交互模式(進入容器內部)啓動。依次執行如下命令:

//啓動一個dotnet鏡像
$ docker run -it microsoft/dotnet
//建立項目名爲HelloDocker.Web的.NET Core MVC項目
dotnet new mvc -n HelloDocker.Web
//進入HelloDocker.Web文件夾
cd HelloDocker.Web
//啓動.NET Core MVC項目
dotnet run
複製代碼

運行結果以下所示:

[root@iZ288a3qazlZ ~]# docker run -it microsoft/dotnet
root@816b4e94de67:/# dotnet new mvc -n HelloDocker.Web
The template "ASP.NET Core Web App (Model-View-Controller)" was created successfully.
This template contains technologies from parties other than Microsoft, see https://aka.ms/template-3pn for details.

Processing post-creation actions...
Running 'dotnet restore' on HelloDocker.Web/HelloDocker.Web.csproj...
  Restoring packages for /HelloDocker.Web/HelloDocker.Web.csproj...
  Generating MSBuild file /HelloDocker.Web/obj/HelloDocker.Web.csproj.nuget.g.props.
  Generating MSBuild file /HelloDocker.Web/obj/HelloDocker.Web.csproj.nuget.g.targets.
  Restore completed in 1.83 sec for /HelloDocker.Web/HelloDocker.Web.csproj.
  Restoring packages for /HelloDocker.Web/HelloDocker.Web.csproj...
  Restore completed in 376.14 ms for /HelloDocker.Web/HelloDocker.Web.csproj.

Restore succeeded.

root@816b4e94de67:/# cd HelloDocker.Web
root@816b4e94de67:/HelloDocker.Web# dotnet run
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
      No XML encryptor configured. Key {727df196-978f-4df8-b3d3-e92a77e410ee} may be persisted to storage in unencrypted form.
Hosting environment: Production
Content root path: /HelloDocker.Web
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
複製代碼

鍵盤按住Ctrl+C便可關閉應用,輸入exit便可退出當前容器。

是否是簡單的幾步就完成了一個.NET Core MVC項目的建立和運行?!這個時候你可能會好奇,Linux宿主機上並無安裝.NET Core SDK啊,MVC項目是如何建立的呢?這就是Docker神奇的地方,咱們從鏡像倉庫中拉取的dotnet鏡像,包含了建立、構建、運行.NET Core項目所需的一切依賴和運行時環境。

退出容器以後,執行find -name HelloDocker.Web(查找HelloDocker.Web文件),咱們發現並無找到。這說明咱們剛纔建立的.NET Core MVC項目是在容器內部建立的,是與宿主機徹底隔離的。這個時候你可能會想,每次都要在容器中安裝源代碼太不方便了,咱們能不能讓容器運行咱們宿主機的源代碼項目?嗯,這是個好問題。下面咱們就來解答這個問題。

5.3. 掛載源代碼

爲了在宿主機上建立.NET Core 項目,這個時候咱們就須要在Linux宿主機上安裝.NET Core SDK。

5.3.1. 宿主機安裝.NET Core SDK

步驟以下:

sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
sudo sh -c 'echo -e "[packages-microsoft-com-prod]\nname=packages-microsoft-com-prod \nbaseurl= https://packages.microsoft.com/yumrepos/microsoft-rhel7.3-prod\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/dotnetdev.repo'
sudo yum update
sudo yum install libunwind libicu
sudo yum install dotnet-sdk-2.1.3
複製代碼

安裝完畢後,咱們依次執行如下命令建立一個.NET Core MVC項目:

//回到根目錄
$ cd $HOME
//建立demo文件夾
$ mkdir demo
$ cd demo
//建立項目名爲HelloDocker.Web的.NET Core MVC項目
dotnet new mvc -n HelloDocker.Web
//進入HelloDocker.Web文件夾
cd HelloDocker.Web
//啓動.NET Core MVC項目
dotnet run
複製代碼

若是知道本機的ip地址的話(可使用ifconfig命令查詢),直接瀏覽器訪問http://<ip address>:5000便可訪問咱們剛剛運行的MVC項目。

這一步咱們就在$HOME/demo/HelloDocker.Web目錄下成功建立了MVC項目,下一步咱們就將該目錄下的源碼項目經過掛載的方式共享到容器中去。

5.3.2. 掛載宿主機項目到容器中

在啓動Docker鏡像時,Docker容許咱們經過使用-v參數掛載宿主機的文件到容器的指定目錄下。換句話說,就至關於宿主機共享指定文件供容器去訪問。廢話很少說,實踐出真知。

// 命令中的`\`結合`Enter`鍵構成換行符,容許咱們換行輸入一個長命令。
$ docker run -it \
-v $HOME/demo/HelloDocker.Web:/app \
microsoft/dotnet:latest
複製代碼

上面的命令就是把$HOME/demo/HelloDocker.Web文件夾下的文件掛載到容器的\app目錄下。

[root@iZ288a3qazlZ HelloDocker.Web]# docker run -it \
> -v $HOME/demo/HelloDocker.Web:/app \
> microsoft/dotnet:latest
root@d70b327f4b7e:/# ls
app  bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@d70b327f4b7e:/# cd app
root@d70b327f4b7e:/app# ls
Controllers  HelloDocker.Web.csproj  Models  Program.cs  Startup.cs  Views  appsettings.Development.json  appsettings.json  bundleconfig.json  obj  wwwroot
root@d70b327f4b7e:/app# dotnet run
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
      No XML encryptor configured. Key {09a69edf-c1c5-4909-ad24-15a43a572fca} may be persisted to storage in unencrypted form.
Hosting environment: Production
Content root path: /app
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
複製代碼

從上面的執行結果來看,容器內部中的app目錄下包含了宿主機上的源碼項目。 上面說到是以共享的形式,而不是容器擁有一份宿主機目錄的拷貝,意味着,在宿主機上對目錄的更改,會即時反應到容器中。但反過來,容器中對共享目錄的更改,不會反應到宿主機上,否則就打破了容器具備的隔離特性。

經過這樣一個簡單場景,聰明的你是否會聯想到這一場景在咱們平常編碼的應用之處呢?是的,咱們能夠用來持續構建(CI)。基本思路是,經過git clone源碼到宿主機上,而後將源碼目錄掛載到容器中去進行構建。

5.4. 藉助Dockerfile

Dockerfile用來定義你將要在容器中執行的系列操做。咱們來建立第一個Dockerfile:

//確保進入咱們建立的MVC項目目錄中去
$ cd $HOME/demo/HelloDocker.Web
//使用touch命令建立Dockerfile
$ touch Dockerfile
//使用vi命令編輯Dockerfile
vi Dockerfile
複製代碼

進入VI編輯界面後,複製如下代碼,使用shift + Ins命令便可粘貼。而後按ESE退出編輯模式,按shift + :,輸入wq便可保存並退出編輯界面。

FROM microsoft/dotnet:latest
WORKDIR /app
COPY . /app
RUN dotnet restore
EXPOSE 5000
ENV ASPNETCORE_URLS http://*:5000
ENTRYPOINT ["dotnet","run"]
複製代碼

上面的命令我依次解釋一下:

  1. 使用FROM指定容器使用的鏡像
  2. 使用WORKDIR指定工做目錄
  3. 使用COPY指令,複製當前目錄(其中.即表明當前目錄)到容器中的/app目錄下
  4. 使用RUN命令指定容器中執行的命令
  5. 使用EXPOSE指定容器暴露的端口號
  6. 使用ENV指定環境參數,上面用來告訴.NETCore項目在全部網絡接口上監聽5000端口
  7. 使用ENTRYPOINT制定容器的入口點

Dockerfile就緒,咱們就能夠將咱們當前項目打包成鏡像以分發部署。 使用docker build -t <name> <path>指令打包鏡像:

$ docker build -t hellodocker.web .
複製代碼

以上命令就是告訴docker將當前目錄打包成鏡像,並命名爲hellodocker.web。命令執行完畢,輸入docker images便可看到咱們新打包的鏡像。鏡像建立完畢咱們就能夠直接運行了:

docker run -d -p 80:5000 hellodocker.web
複製代碼

上面的指令就是運行咱們新打包的鏡像,並經過-p參數映射容器的5000到宿主機的80端口,其中-d參數告訴docker之後臺任務形式運行鏡像。由於80是默認的web端口,因此咱們經過瀏覽器直接訪問ip便可訪問到咱們容器中運行的MVC網站。或者經過curl -i http://localhost來驗證。操做示例以下:

[root@iZ288a3qazlZ HelloDocker.Web]# docker build -t hellodocker.web .
Sending build context to Docker daemon   3.3 MB
Step 1 : FROM microsoft/dotnet:latest
 ---> 7d4dc5c258eb
Step 2 : WORKDIR /app
 ---> Using cache
 ---> 98d48a4e278c
Step 3 : COPY . /app
 ---> d5df216b274a
Removing intermediate container 0a70f0f2b681
Step 4 : RUN dotnet restore
 ---> Running in 0c8a9c4d5ba1
  Restore completed in 939.01 ms for /app/HelloDocker.Web.csproj.
  Restoring packages for /app/HelloDocker.Web.csproj...
  Restore completed in 1.38 sec for /app/HelloDocker.Web.csproj.
 ---> 479f6b5cc7f0
Removing intermediate container 0c8a9c4d5ba1
Step 5 : EXPOSE 5000
 ---> Running in f97feceb7f1b
 ---> 562a95328196
Removing intermediate container f97feceb7f1b
Step 6 : ENV ASPNETCORE_URLS http://*:5000
 ---> Running in 403d8e2e25a6
 ---> 16b7bd572410
Removing intermediate container 403d8e2e25a6
Step 7 : ENTRYPOINT dotnet run
 ---> Running in 0294f87ce3fd
 ---> 532e44a7fd54
Removing intermediate container 0294f87ce3fd
Successfully built 532e44a7fd54
[root@iZ288a3qazlZ HelloDocker.Web]# docker run -d -p 80:5000 hellodocker.web
9d28bb3fa553653e4c26bf727715c82a837a2c224a0942107f3fab08c0a2686d
[root@iZ288a3qazlZ HelloDocker.Web]# curl -i http://localhost
HTTP/1.1 200 OK
Date: Sat, 23 Dec 2017 14:23:15 GMT
Content-Type: text/html; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
複製代碼

至此,咱們藉助Docker就完美的完成了.NET Core項目的容器化部署。

結束了?尚未!

我打包的鏡像是保存在本地的,我如何把鏡像部署到其餘機器上呢?請繼續看。

6. 推送鏡像到倉庫

在第三節中,咱們就簡要介紹了,有個Registry是專門用來存儲鏡像的。請自行到Docker Hub註冊個帳號,而後咱們把本地打包的鏡像放到本身帳號下的倉庫下不就得了?! 註冊完畢後,執行docker login

[root@iZ288a3qazlZ HelloDocker.Web]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username: shengjie Password: Login Succeeded [root@iZ288a3qazlZ HelloDocker.Web]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE hellodocker.web latest 532e44a7fd54 13 minutes ago 1.745 GB 複製代碼

再執行docker push

$ docker push hellodocker.web
Error response from daemon: You cannot push a "root" repository. Please rename your repository to docker.io/<user>/<repo> (ex: docker.io/shengjie/hellodocker.web)
複製代碼

推送失敗,提示咱們的鏡像命名不符規範。原來在推送以前要把鏡像按<user>/<repo>格式來命名。那如何重命名呢,咱們用打標籤的方式重命名:

$ docker tag hellodocker.web shengjie/hellodocker.web:v1
$ docker images
REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
hellodocker.web                      latest              532e44a7fd54        35 minutes ago      1.745 GB
yanshengjie/hellodocker.web          v1                  532e44a7fd54        35 minutes ago      1.745 GB
$ docker push shengjie/hellodocker.web
The push refers to a repository [docker.io/shengjie/hellodocker.web]
774b128a8c4f: Pushed
7bf42a9b5527: Pushed
bd7f01c2dc6f: Pushed
....
複製代碼

換一臺機器,咱們直接執行如下命令,就完成了多重部署。

docker run -p 80:5000 <username>/hellodocker.web:v1
複製代碼

7.最後

若是你一步一步跟着練習的話,相信你對Docker以及.NET Core的跨平臺特性有了初步的理解,也相信你對Docker的Build, Ship, and Run Any App, Anywhere有了更深的體會。

本文的實戰演練就先到這裏,下一篇,咱們來看如何藉助Docker完成.NET Core Web項目的分佈式部署!!!

參考資料

Hello Docker HOSTING .NET CORE ON LINUX WITH DOCKER - A NOOB'S GUIDE Docker命令收集 Linux經常使用命令

相關文章
相關標籤/搜索