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


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

概要

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

網站本體 dockerfile

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

# 使用官方 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 的初始化目錄 例如

-- 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);

底下是預儲程序的範例

-- 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

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的值改成自己環境用的

# 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,這樣就可以在這個設定檔下將資料庫指向到測試資料庫

// 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 的設定來啟動或偵錯網站

    "Notebook": {
      "commandName": "Project",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Notebook"
      },
      "dotnetRunMessages": true,
      "applicationUrl": "https://localhost:7134;http://localhost:5020"
    },