[Docker] 使用 docker-compose 建立多個服務
公司一直有一個維護的案子,該維護案的開發環境都一直放在雲端上,例如 SQL Server、後端 API 等等…。 但是該維護案又不會常常使用到開發環境,但是沒有開發環境偶爾要維護又很麻煩,所以為了節省成本,就決定把該開發環境容器化,並且把放在雲端的服務關掉。
該維護案是前後端分離,前端是 Angular
後端是 ASP.NET Core API
與 SQL Server
,所以要容器化的是 後端 的部分,只要將後端容器化後,前端開發就不用煩惱後端環境怎麼建立。
所以今天要介紹如何用 docker-compose
建立 ASP.NET Core API 與 SQL Server 服務,並且該 API 會連 SQL Server 當作資料來源。 讓前端的開發工程師在開發的時候,不用為了後端的環境而煩惱。
環境說明
這次的 demo 我建立了一個 ASP.NET Core 的專案,且該專案用 EF Core 對資料庫做操作,以及建立了一個含有 northwnd 資料庫的 SQL Server 映像檔。
ASP.NET Core 專案說明
我有將專案放到 Github 上供參考 ASP.NET Core API 專案 。
該專案就是一個非常簡單的 API ,只有一個 Controller ,一個 API ,該 API 就是讀取資料庫,撈出一筆資料後丟出來。 如下方程式碼
- cs
1 | [ ] |
而該專案的資料夾,請參考下圖,會專注在 docker-compose.yml
上。 其中 Dockerfile 是用來建置後端 API ,可以參考這篇 [Docker] 多階段建置映像檔 (multi-stage build),以 ASP.NET Core 為例
範例資料庫說明
我有將範例的資料庫推上我的 docker hub - docker/mileslin/northwnd ,直接 docker run -e "ACCEPT_EULA=Y" -p 1433:1433 -d mileslin/northwnd
就可以把 northwnd 資料庫執行起來。 (但是我們今天不是要單獨執行,所以可以先不用執行此指令。)
資料庫登入資訊
- port: 1433
- 帳號: sa
- 密碼: 2wsx#EDC
若要了解如何從無到有建立 SQL Server 映像檔,可以參考 [Docker] SQL Server Container 快速入門 。
看懂 docker-compose.yml
環境說明結束了,現在就是來使用 docker-compose 建立服務啦。 如果還不知道什麼是 docker-compose? 可以先看一下官方說明。
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. To learn more about all the features of Compose, see the list of features.
簡單來說 docker-compose 就是用來定義一次執行多個容器的工具。
所以我們現在要做的就是,要寫一個 docker-compose.yml 檔案,該檔案會定義我要建立的 docker 服務,並且使用 docker-compose
來啟動服務。 那接下來我就來帶大家看這份 docker-compose.yml 檔案吧。
1 | # 使用 Compose file format V3.2 版本 |
depends_on 設定說明
雖然上面有設定 myapi depends_on mydb ,但是請注意,就算 mydb 的 service 先啟動,不代表資料庫服務已經起來,還是需要等一段時間,資料庫的實體才會起來,在這段時間可能會造成 myapi 無法連線的問題。 如果要處理這個問題,需要使用 wait-for-it。
Docker 預設的 DNS
這裡要額外補充說明的是,為什麼 SQL Server 的位址是 mydb 這個服務的名稱?
只要是 docker services 在同一個自訂義網路的情況下,docker 的 DNS 會從 service 的名稱解析到該 service 的位址。 所以以上方的範例,我將 mydb 與 myapi 都加入一個自訂義網路,名為 demonetwork ,所以我的 myapi 服務在設定資料庫連線字串的時候,可以使用 mydb 當作資料庫的位址,docker 的 DNS 就會幫我導到該資料庫去。 參考: Embedded DNS server in user-defined networks
請注意,如果 service 不是建立在自訂義的網路,而是預設的 bridge 網路,則 docker 的 DNS 服務需要額外做設定。
參考: Configure container DNS
使用 docker-compose 指令啟動服務與移除服務
現在萬事都準備好了,只剩下把服務啟動, 執行 docker-compose -f docker-compose.yml up
,就會看到下圖的情況,docker-compose 會把在 yml 裡面定義好的服務都啟動。
因為 docker-compose.yml 是 docker 預設會找到檔案,所以 -f docker-compose.yml
不一定要設定,也可以使用此指令 docker-compose up
效果是一樣的。
服務起來後,我們來看一下 http://localhost:8000/api/values 是不是真的能夠連到資料
上圖可以知道,我們已經成功連到資料,且該資料是從資料庫來的!!
那接下來,要移除服務也很簡單,只要輸入 docker-compose down
就可以把所以服務移除。
如果啟動服務要背景執行的話,可以加入 -d 參數,如: docker-compose -f docker-compose.yml up -d
這樣 service 就會在背景執行了
其他 docker-compose 指令
docker-compose 也可以對單一 service 做操作,例如,我要停止 myapi service,我就可以使用 docker-compose stop myapi
,重新啟動 myapi service,就可以使用 docker-compose start myapi
。
請參考下圖,我使用 docker-compose ps
來觀察停止服務與啟動服務的狀態
重新建置 myapi 的方式
如果 myapi 的程式碼有調整,想要更新的話,是沒辦法直接 docker-compose down
+ docker-compose up
就更新的,因為有 cache 的問題,所以如果重新建置的話,要用其他方式,我這邊介紹兩種做法。
方法一
把 myapi 的 image 刪除,再重新 docker-compose up
請參考下方指令
docker-compose images
找到要刪除的 image iddocker-compose stop myapi
,docker-compose rm myapi
停止與刪除 myapi servicedocker rmi 46ccc
刪除 myapi 的 image ,docker-compose up
重新啟動服務rebuild service - bash
1
2
3
4
5docker-compose images
docker-compose stop myapi
docker-compose rm myapi
docker rmi 46ccc
docker-compose up
執行成功後,會看到下圖的樣子
方法二
重新建置該 service ,這方法是參考 How to restart a single container with docker-compose 的說明。
只要執行下面 4 行指令就可以直接重 build 了。
- bash
1 | docker-compose stop myapi |
小結
如果讀者要直接執行的話,可以到我的專案範例 docker-compose-demo 下載下來後,直接 docker-compose up 就可以把服務執行起來了。 剩下的只要看懂 yml 在寫什麼,就可以很輕易運用到自己的專案上了。
延伸閱讀
[Overview of Docker Compose]
[Get started with Docker Compose]
[Overview of docker-compose CLI]