使用 docker-compose 建立本地測試環境

最主要是想要解決開發過程中,非常依賴 LAB 環境所提供的資料庫,一旦 LAB 環境無法使用,就無法進行開發,因此透過 docker-compose 建立本地測試環境,來解決這個問題
當然後續因為懶惰我也沒有完全做完(因為依賴的不只是資料庫,還有其他服務),但是這個方法是可行的,提供參考

概要

  1. 網站本體,需要先將網站自己本身的 dockerfile 準備好
  2. 資料庫,這邊使用 mysql 並且假設只有一個資料庫的依賴用做示範
  3. adminer,這是一個簡單的資料庫管理工具,用來管理 mysql 的資料庫

網站本體 dockerfile

實際發布文章的話需要改寫成簡單的範本,應該用預設的 asp.net mvc 範本就可以了
大概長這樣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 使用官方 ASP.NET Core Runtime 作為基礎映像
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

# 使用官方 ASP.NET Core SDK 作為建置映像的基礎
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["YourAspNetMvcProject.csproj", "YourAspNetMvcProject/"]
RUN dotnet restore "YourAspNetMvcProject/YourAspNetMvcProject.csproj"
COPY . .
WORKDIR "/src/YourAspNetMvcProject"
RUN dotnet build "YourAspNetMvcProject.csproj" -c Release -o /app/build

# 進行發行
FROM build AS publish
RUN dotnet publish "YourAspNetMvcProject.csproj" -c Release -o /app/publish

# 開始建立最終映像,將發行版拷貝到官方 ASP.NET Core Runtime 映像中
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "YourAspNetMvcProject.dll"]

資料庫 docker-compose

直接透過 docker-compose 建立,並給予設定好預設的 root 密碼就可以了,當然也要包含初始化資料庫的 sql 檔案
將其放置於特定目錄,例如專案下的 sql-init 目錄,並且再透過 docker-compose 的設定 volume 來將其掛載到 mysql 的初始化目錄
例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- sql-init/init-db.sql
CREATE DATABASE IF NOT EXISTS mydb DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
USE mydb;

CREATE TABLE mydb.main_info (
id INT(11) NOT NULL AUTO_INCREMENT COMMENT 'Id',
name VARCHAR(255) NOT NULL COMMENT '名稱',
is_del SMALLINT(1) NOT NULL DEFAULT 0 COMMENT '是否虛擬刪除',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
created_by INT(11) NOT NULL DEFAULT 0 COMMENT '建立人員',
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新時間',
updated_by INT(11) NOT NULL DEFAULT 0 COMMENT '更新人員',
PRIMARY KEY (id)
)
ENGINE = INNODB,
CHARACTER SET utf8mb4,
COLLATE utf8mb4_unicode_ci;

SET NAMES 'utf8';

INSERT INTO mydb.main_info(id, name, is_del, created_at, created_by, updated_at, updated_by)
VALUES (1, '測試', 0, '2024-01-18 11:54:57', 31, '2024-01-18 18:26:02', 31);

底下是預儲程序的範例

1
2
3
4
5
6
7
8
9
10
11
-- sql-init/init-usp.sql
USE mydb;

DELIMITER $$

CREATE PROCEDURE `usp_main_info_get`(IN `@id` int)
BEGIN
select p.name from main_info p where p.id = `@id`;
END $$

DELIMITER ;

指定 mysql_native_password 是因為新版的 mysql 預設的驗證方式是 caching_sha2_password,這樣會導致一些舊的程式無法連線到 mysql

1
2
3
4
5
6
7
8
9
db:
image: mysql:5.7.19
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_ROOT_PASSWORD: example
ports:
- "3306:3306"
volumes:
- ./sql-init/:/docker-entrypoint-initdb.d/

adminer

透過 adminer 來管理 mysql 的資料庫,這邊直接使用官方的 image 就可以了

建立 docker-compose 測試環境

這裡的 environment 是因為 LAB 環境不能直接連外面所以要透過 proxy,如果只是模擬需求中的BLOG 文章發布,應該不需要這個設定;如果真的需要,就把 proxy的值改成自己環境用的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# docker-compose.yml
version: "3.7"
services:
web:
build:
context: .
dockerfile: Dockerfile
ports:
- "80:80"
- "443:443"
environment:
http_proxy: ${HTTP_PROXY}
https_proxy: ${HTTP_PROXY}
ftp_proxy: ${HTTP_PROXY}
no_proxy: .company.net
ASPNETCORE_ENVIRONMENT: Notebook
db:
image: mysql:5.7.19
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_ROOT_PASSWORD: example
ports:
- "3306:3306"
volumes:
- ./sql-init/:/docker-entrypoint-initdb.d/
adminer:
image: adminer:4.8.1
ports:
- 8080:8080

搭配 ASPNETCORE_ENVIRONMENT 來設定環境變數 Notebook,這樣就可以在這個設定檔下將資料庫指向到測試資料庫

1
2
3
4
5
6
// appsettings.Notebook.json
{
"ConnectionStrings": {
"DB_connection": "server=db;port=3306;user id=root;password=example;database=mydb;sslmode=none;charset=utf8mb4;ConnectionTimeout=30;"
}
}

為了手動方便起見,也在 launchSettings.json 中設定 ASPNETCORE_ENVIRONMENT,這樣就可以直接透過 IDE 使用這份 Notebook 的設定來啟動或偵錯網站

1
2
3
4
5
6
7
8
9
"Notebook": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Notebook"
},
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7134;http://localhost:5020"
},