說在前面#
在閱讀本文之前,您必須對 Docker 的中涉及的基本概念以及常見命令有一定了解,本文側重實戰,不會對相關概念詳述。
同時請確保您本地開發機器已完成如下安裝:
- Docker 18.06 或更高版本的 Docker 客戶端
- .NET Core SDK 2.2 或更高版本
- Visual Studio Code 代碼編輯器,以及 C# 語法插件 1.17.1 或更高版本
注:本文實驗環境是 Ubuntu 18.04 LTS。如果您的機器是 Window,也可以把 Docker 裝在虛擬機或服務器上。
創建演示項目#
開始之前要先准備一個需要 Docker 容器化的 ASP.NET Core 應用程序,用於下面的操作演示。這里我用 .NET Core CLI 快速搭建一個全新的 Web API 項目。
啟動 VS Code,打開集成終端,輸入如下命令:
以上便創建了一個名為TodoApi
的 Web API 樣板項目。
打開集成終端,輸入dotnet run
命令編譯運行程序,然后打開瀏覽器跳轉到 URL http://localhost:5000/api/values
,如正常返回如下 JSON 數據,說明應用程序本地成功運行。
現在讓我們更進一步,在 Docker 中構建並運行該應用程序。
創建 Dockerfile 文件#
Dockerfile 是一個文本文件,其用來定義單個容器的內容和啟動行為,按順序包含構建鏡像所需的所有指令。Docker 會通過讀取 Dockerfile 中的指令自動構建鏡像。
在項目TodoApi
根目錄中,創建一個名為Dockerfile
的文件,並粘貼以下內容:
FROM
指令必須放在第一位,用於初始化鏡像,為后面的指令設置基礎鏡像。
WORKDIR
指令為其他指令設置工作目錄,如果不存在,則會創建該目錄。
COPY
指令會從源路徑復制新文件或目錄,並將它們添加到路徑目標容器的文件系統中。
RUN
指令可以在當前鏡像之上的新 層 中執行任何命令並提交結果,生成的已提交鏡像將用於 Dockerfile 中的下一步。
ENTRYPOINT
指令支持以可執行文件的形式運行容器。
有關 Dockerfile 中指令用法的更多信息請參閱 Dockerfile reference。
同時,為了避免構建項目中的一些調試生成文件,可以在項目文件夾中新增.dockerignore
文件,並粘貼如下內容:
構建應用容器鏡像#
在項目TodoApi
根目錄中,打開集成終端,執行如下命令構建容器鏡像:
-t
參數用來指定鏡像的名字及標簽,通常是name:tag
或者name
格式。本例todoapi
便是我們給鏡像起的名字,沒有設置標簽即使用默認標簽latest
。
如命令執行成功,終端會有類似如下輸出:
如果您的機器是第一次構建,速度可能會有些慢,因為要從 Docker Hub 上拉取應用依賴的
dotnet-sdk
和aspnetcore-runtime
基礎鏡像。
構建完成后,我們可以通過docker images
命令確認本地鏡像倉庫是否存在我們構建的鏡像todoapi
。
運行應用容器#
容器鏡像構建完成后,就可以使用docker run
命令運行容器了,有關該命令參數的更多信息請參閱 Reference - docker run 。
開發環境下,通常會通過docker run --rm -it
命令運行應用容器,具體命令如下:
-it
參數表示以交互模式運行容器並為容器重新分配一個偽輸入終端,方便查看輸出調試程序。
--rm
參數表示將會在容器退出后自動刪除當前容器,開發模式下常用參數。
-p
參數表示會將本地計算機上的5000
端口映射到容器中的默認80
端口,端口映射的關系為host:container
。todoapi
便是我們要啟動的本地鏡像名稱。
如命令執行成功,終端會有類似如下輸出:
生產環境下,通常會通過docker run -d
命令運行應用容器,具體命令如下:
-d
參數表示會將容器作為服務啟動,不需要終端交互。--name
參數用來指定容器名稱,本例指定容器名稱為myapp
。--restart
是一個面向生產環境的參數,用來指定容器非正常退出時的重啟策略,本例always
表示始終重新啟動容器,其他可選策略請參考 Restart policies (--restart)。
如命令執行成功,終端會有類似如下輸出:
容器啟動后,在 Web 瀏覽器中再次訪問http://localhost:5000/api/values
,應該會和本地測試一樣返回如下 JSON 數據:
至此,我們的 ASP.NET Core 應用就成功運行在 Docker 容器中了。
多容器應用部署#
目前我們創建的演示項目TodoApi
過於簡單,真實的生產項目肯定會涉及更多其他的依賴。例如:關系數據庫 Mysql、文檔數據庫 MongoDB、分布式緩存 Redis、消息隊列 RabbitMQ 等各種服務。
還有就是,生產環境我們一般不會將 ASP.NET Core 應用程序的宿主服務器 Kestrel 直接暴露給用戶,通常是在前面加一個反向代理服務 Nginx。
這些依賴服務還要像傳統部署方式那樣,一個一個單獨配置部署嗎?不用的,因為它們本身也是可以被容器化的,所以我們只要考慮如何把各個相互依賴的容器聯系到一起,這就涉及到容器編排,而 Docker Compose 正是用來解決這一問題的,最終可以實現多容器應用的一鍵部署。
Docker Compose 是一個用於定義和運行多容器的 Docker 工具。其使用
YAML
文件來配置應用程序的服務,最終您只要使用一個命令就可以從配置中創建並啟動所有服務。
安裝 Docker Compose#
Linux 系統下的安裝過程大致分為以下幾步:
Step1:運行如下命令下載 Compose 最新穩定版本,截止發稿前最新版本為1.24.0
。
Step2:對下載完成的二進制程序添加可執行權限。
Step3:測試安裝是否成功。
若您在安裝過程中遇到問題,或是其他系統安裝請參閱 Install Docker Compose。
改造演示項目#
現在來改造一下我們的演示項目TodoApi
,添加 Redis 分布式緩存、使用 Nginx 做反向代理,准備構建一個具如下圖所示架構的多容器應用。
在TodoApi
項目根目錄下,打開集成終端,輸入如下命令新增 Redis 依賴包。
修改應用啟動配置文件Startup.cs
中的ConfigureServices
方法:
在TodoApi
項目Controllers
目錄下新建控制器HelloController
,具體代碼如下所示:
以上控制器,提供了兩個接口/api/hello
和/api/hello/{name}
,分別用來測試 Nginx 負載均衡和 Redis 的聯通性。
創建 docker-compose.yml#
准備工作就緒,下面我們就可以使用 Docker Compose 來編排容器。
同樣是在TodoApi
項目根目錄中,創建一個名為docker-compose.yml
的文件,並粘貼以下內容:
其中version
用來指定 Compose 文件版本號,3.7
是目前最新版本,具體哪些版本對應哪些特定的 Docker 引擎版本請參閱 Compose file versions and upgrading。
Compose 中強化了服務的概念,簡單地理解就是, 服務是一種用於生產環境的容器。一個多容器 Docker 應用由若干個服務組成,如上文件即定義了 5 個服務:
- 3 個應用服務
myproject-todoapi-1
、myproject-todoapi-2
和myproject-todoapi-3
- 1 個 Nginx 服務
myproject-reverse-proxy
- 1 個 Redis 服務
myproject-redis
以上 5 個服務的配置參數相差無幾、也很簡單,我就不展開敘述,不清楚的可以參閱 Compose file reference。
這里只講一個配置參數volumes
:
我們知道,容器中的文件在宿主機上存在形式復雜,修改文件需要先通過如下命令進入容器后操作。
容器一旦刪除,其內部配置以及產生的數據也會丟失。
為了解決這些問題,Docker 引入了數據卷 volumes 機制。即 Compose 中 volumes 參數用來將宿主機的某個目錄或文件映射掛載到 Docker 容器內部的對應的目錄或文件,通常被用來靈活掛載配置文件或持久化容器產生的數據。
PS:自己動手編寫
docker-compose.yml
的時候,可以嘗試實驗更多場景。比如:新增一個 MySQL 依賴服務、把容器內產生的數據持久化到宿主機等等。
創建相關配置文件#
接下來,需要根據如上docker-compose.yml
文件中涉及的volumes
配置創建三個配置文件。要知道,它們最終是需要被注入到 Docker 容器中的。
首先,在TodoApi
項目根目錄中,創建三個應用服務myproject-todoapi-*
需要的程序配置文件appsettings.json
,具體內容如下:
以上配置,指定了 Redis 服務myproject-redis
的連接字符串,其中myproject-redis
可以看到是 Redis 服務的服務名稱,當該配置文件注入到 Docker 容器中后,會自動解析為容器內部 IP,同時考慮到 Redis 服務的安全性,為其指定了密碼,即password=todoapi@2019
。
然后,在TodoApi
項目根目錄中創建一個子目錄conf
,用來存放 Nginx 和 Redis 的配置文件。
先來創建 Redis 服務myproject-redis
的配置文件。
可以通過如下命令,下載一個 Redis 官方提供的標准配置文件redis.conf
:
然后打開下載后的redis.conf
文件,找到SECURITY
節點,根據如上應用服務的 Redis 連接字符串信息,啟用並改下密碼:
再來創建 Nginx 服務myproject-nginx
的配置文件。
在conf
目錄中,創建一個名為nginx.conf
的配置文件,並粘貼如下內容:
以上配置,是一個 Nginx 中具備負載均衡的代理配置,其默認采用輪循策略將請求轉發給 Docker 服務myproject-todoapi-1
、myproject-todoapi-2
和myproject-todoapi-3
。
運行並測試多容器應用#
經過以上幾個小節,容器編排的過程就完成了,接下來就可以直接定義並啟動我們創建的多容器應用實例了。
切換到docker-compose.yml
文件所在的目錄,也就是TodoApi
項目的根目錄,執行如下命令:
如命令執行成功,終端最后會有類似如下輸出:
至此,我們的多容器應用就已經在運行了,可以通過docker-compose ps
命令來確認下。
可以通過連續三次請求/api/hello
接口測試應用的負載均衡。
三個應用服務分別部署在不同容器中,所以理論上來講,他們的容器內部 IP 也是不同的,所以/api/hello
接口每次輸出信息不會相同。
請求/api/hello/{name}
接口測試 Redis 服務連通性。
小結#
本文從零構建了一個 ASP.NET Core 應用,並通過 Docker 部署,然后由淺入深,引入 Docker Compose 演示了多容器應用的部署過程。通過本文的實戰您可以更深入地了解 Docker。本文涉及的代碼已托管到以下地址,您在實驗過程中遇到問題可以參考。
https://github.com/esofar/dockerize-aspnetcore-samples
Docker 命令附錄#
Docker Compose 命令附錄#
相關閱讀#
- ASP.NET Core Docker Sample
- Dockerize a .NET Core application
- Best practices for writing Dockerfiles
- Fun With Docker-Compose Using .NET Core And NGINX
- ASP.NET Core 2.2: implementando Load Balancing com Nginx, Docker e Docker Compose
轉自:https://www.cnblogs.com/esofar/p/10694319.html?from=timeline