.Net Core微服務入門全紀錄(八)——Docker Compose與容器網絡
Tips:本篇已加入系列文章閱讀目錄,可點擊查看更多相關文章。
前言
上一篇【.Net Core微服務入門全紀錄(七)——IdentityServer4-授權認證】中使用IdentityServer4完成了鑒權中心的搭建,配合網關實現了統一的授權認證。進行到這裡,系統環境已經比較複雜了,想把整個系統運行起來會非常繁瑣:要運行Consul、業務服務、網關、鑒權中心、web客戶端,還要安裝數據庫、MQ等等。。。那麼本篇將使用Docker Compose來解決以上問題,僅需一個簡單的命令,即可啟動整個環境。
Docker Compose
什麼是Docker Compose?
Compose 是用於定義和運行多容器 Docker 應用程序的工具。通過 Compose,您可以使用 YML 文件來配置應用程序需要的所有服務。然後,使用一個命令,就可以從 YML 文件配置中創建並啟動所有服務。
簡單來理解,Compose類似一個批量工具,可以執行一組命令,支持批量構建鏡像,批量啟動容器,批量刪除容器等等功能。
Windows的Docker Desktop中已經包括了Compose,Linux下Compose則需要單獨安裝一下。
yml file
yml文件是使用Compose必不可少的,在編寫yml文件之前還需要準備Dockerfile。
之前的章節中,有些服務不是在Docker中運行的,現在全部放到Docker中。確保解決方案中每個項目都添加Docker支持。
在根目錄新建docker-compose.yml文件:
以下是docker-compose.yml文件內容:
version: '3.4' #Compose文件版本
services: #服務
auth: #定義"auth"服務 對應的是鑒權中心項目
build: #構建
context: . #構建上下文(目錄)
dockerfile: ./IDS4.AuthCenter/Dockerfile #Dockerfile文件目錄
ports: #端口
- '9080:9080' #容器外部9080 容器內部9080
environment: #環境變量
- ASPNETCORE_URLS=//+:9080 #程序在容器內部//+:9080運行 也可以寫成//0.0.0.0:9080
networks: #容器網絡
- my-net #自定義網絡my-net
web: #定義"web"服務 對應的web客戶端項目
build:
context: .
dockerfile: ./Web.MVC/Dockerfile
ports:
- '5000:5000'
environment:
- ASPNETCORE_URLS=//+:5000
networks:
- my-net
depends_on: #"web"服務依賴於"auth"服務和"apigateway"服務,此服務會在依賴服務之後執行
- auth
- apigateway
apigateway: #定義"apigateway"服務 對應的網關項目
build:
context: .
dockerfile: ./Ocelot.APIGateway/Dockerfile
ports:
- '9070:9070'
environment:
- ASPNETCORE_URLS=//+:9070
networks:
- my-net
depends_on:
- orderapi1
- orderapi2
- orderapi3
- productapi1
- productapi2
- productapi3
productapi1: #定義"productapi1"服務 對應的產品服務項目
image: productapi #指定鏡像名稱,如果不指定 默認是:netcoremicroservicedemo_productapi1,因為下面要用到所以指定一下
build:
context: .
dockerfile: ./Product.API/Dockerfile
ports:
- '9050:9050'
environment:
- ASPNETCORE_URLS=//+:9050
- ConsulSetting:ServiceIP=productapi1 #程序參數
- ConsulSetting:ServicePort=9050 #程序參數
networks:
- my-net
depends_on:
- consul
- postgres
- rabbitmq
productapi2:
image: productapi #指定鏡像名稱為productapi,productapi1服務中已經構建了productapi鏡像,所以不用重複構建
ports:
- '9051:9051'
environment:
- ASPNETCORE_URLS=//+:9051
- ConsulSetting:ServiceIP=productapi2
- ConsulSetting:ServicePort=9051
networks:
- my-net
depends_on:
- productapi1
productapi3:
image: productapi
ports:
- '9052:9052'
environment:
- ASPNETCORE_URLS=//+:9052
- ConsulSetting:ServiceIP=productapi3
- ConsulSetting:ServicePort=9052
networks:
- my-net
depends_on:
- productapi1
orderapi1:
image: orderapi
build:
context: .
dockerfile: ./Order.API/Dockerfile
ports:
- '9060:9060'
environment:
- ASPNETCORE_URLS=//+:9060
- ConsulSetting:ServiceIP=orderapi1
- ConsulSetting:ServicePort=9060
networks:
- my-net
depends_on:
- consul
- postgres
- rabbitmq
orderapi2:
image: orderapi
ports:
- '9061:9061'
environment:
- ASPNETCORE_URLS=//+:9061
- ConsulSetting:ServiceIP=orderapi2
- ConsulSetting:ServicePort=9061
networks:
- my-net
depends_on:
- orderapi1
orderapi3:
image: orderapi
ports:
- '9062:9062'
environment:
- ASPNETCORE_URLS=//+:9062
- ConsulSetting:ServiceIP=orderapi3
- ConsulSetting:ServicePort=9062
networks:
- my-net
depends_on:
- orderapi1
consul:
image: consul #指定鏡像名稱為consul,本地如果沒有consul鏡像,會從docker遠程倉庫拉取
ports:
- '8500:8500'
networks:
- my-net
postgres:
image: postgres
environment:
POSTGRES_PASSWORD: pg123456
networks:
- my-net
rabbitmq:
image: rabbitmq
networks:
- my-net
networks: #定義容器網絡
my-net: #my-net網絡
driver: bridge #網絡模式為bridge
以上yml文件定義了auth,web,apigateway,productapi1,productapi2,productapi3,orderapi1,orderapi2,orderapi3,consul,postgres,rabbitmq 12個服務(容器),和一個容器網絡 my-net。這裡的productapi和orderapi相當於是基於同樣的鏡像各運行了3個容器,這其實不太合理,正常他們應該分佈在多個docker中。。。
文件的內容雖然有點多,但是應該不難理解,上面的關鍵字我都有注釋。下面再簡單介紹一下文件中的networks容器網絡。
容器網路
前面的章節中有提到過,默認情況下容器之間的通訊是比較麻煩的,之前是通過host.docker.internal
或者容器的IP去訪問,雖然是可以訪問但有些不友好。更好的方式是,我們可以自定義一個bridge網絡,將所有服務(容器)加入這個網絡中,那麼容器之間就可以直接通過服務名稱通信了。bridge模式只是docker網絡模式中的一種,有興趣的話可以自行搜索一下。
代碼修改
既然程序都運行在docker中,那就不能寫localhost
,host.docker.internal
之類的主機名了,統一改為docker-compose.yml文件中定義的服務名。如下:
還有多處修改就不全貼出來了,都是些類似的改動。這些配置還是不要寫在代碼里,改動起來比較亂。
這裡有一個特殊的就是identityserver4鑒權服務,這個服務是容器內外部都需要訪問的(容器內部ids4發現文檔等接口的調用,外部瀏覽器訪問),所以不能直接寫服務名auth,寫auth的話外部無法訪問,寫localhost的話內部又無法訪問。最後是參考eShopOnContainers項目,使用docker.for.win.localhost
來滿足內外部的訪問需求:
理論上用host.docker.internal
或許也可以,沒去測試。。。這個配置放到Compose的環境變量里會比較好,這裡只是為了方便。
eShopOnContainers項目是微軟官方出品的開源項目,對於學習微服務,docker等技術非常有幫助。
項目地址://github.com/dotnet-architecture/eShopOnContainers
構建與啟動
完成以上操作後,進入項目根目錄執行docker-compose build
build完成後,執行docker-compose up -d
,-d代表在後台運行
(第一次up,orderapi2,orderapi3,productapi2,productapi3這4個服務會起不來,是因為他們啟動時有創建數據庫的操作,同時啟動會導致後起來的4個重複的服務創建數據庫時報錯,因為orderapi1和productapi1在創建同樣的數據庫。。。這個前面說過的。這裡等up完再執行一次up就好了)
瀏覽器訪問://localhost:5000/
登錄後:
這樣運行系統是不是非常簡單呢?想要摧毀這個環境也很簡單,只需要一句docker-compose down
如果不習慣docker命令,推薦使用vscode,裝一下docker插件,很方便。
總結
上文用到了Docker-Compose的3個命令:
構建:docker-compose build
啟動:docker-compose up
銷毀:docker-compose down
其實build命令也可以省略,執行up時如果沒有build的話會自動build,無論多複雜的系統環境,只需要一個docker-compose up
命令即可啟動。不過鏡像需要重新bulid的時候,還是要用到build命令。Compose還有一些其他命令,需要的話可以自行搜索。
主要的工作量在於docker-compose.yml文件的編寫。
需要代碼的點這裡://github.com/xiajingren/NetCoreMicroserviceDemo