Buy Me a Coffee

解決大專案個別人員Docker image部署front-nextjs 以及 backend-dotnet使用vagrant

引言

在大型軟體開發專案中,確保所有團隊成員使用一致的開發環境是至關重要的。本文將詳細介紹如何使用 Vagrant 來建立一個統一的開發環境,並在其中部署 front-nextjs(基於 Next.js 14)和 backend-dotnet(基於 .NET 8)的 Docker 映像。我們將分別針對 macOS 和 Windows 操作系統提供詳細的安裝和配置說明,幫助開發團隊克服環境差異帶來的挑戰。

macOS 上的 Vagrant 安裝和配置

安裝必要軟體

在 macOS 上,我們需要安裝以下軟體:

  1. Homebrew(如果尚未安裝)
  2. Vagrant
  3. Parallels Desktop(作為虛擬化提供者)

安裝 Homebrew

如果你還沒有安裝 Homebrew,請在終端機中執行以下命令:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

安裝 Vagrant

使用 Homebrew 安裝 Vagrant:

brew install --cask vagrant

安裝 Parallels Desktop

由於我們使用 Parallels Desktop 作為虛擬化提供者,請確保你已經安裝了 Parallels Desktop。如果尚未安裝,可以從 Parallels 官網下載並安裝。

配置 Vagrant

  1. 創建專案目錄:
mkdir vagrant-docker-env
cd vagrant-docker-env
  1. 初始化 Vagrant 配置檔案:
vagrant init
  1. 編輯 Vagrantfile,使用以下內容:
Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-20.04"

  config.vm.provider "parallels" do |prl|
    prl.memory = 2048
    prl.cpus = 2
  end

  config.vm.synced_folder ".", "/vagrant", type: "nfs", mount_options: ['rw', 'vers=3', 'tcp', 'nolock', 'fsc', 'actimeo=2']

  config.vm.network "forwarded_port", guest: 3000, host: 3001
  config.vm.network "forwarded_port", guest: 5000, host: 5001

  config.vm.provision "shell", privileged: false, inline: <<-SHELL
    set -e
    set -x

    echo "正在更新系統包..."
    sudo apt-get update
    sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common

    echo "添加 Docker 官方 GPG key..."
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

    echo "設置 Docker repository..."
    sudo add-apt-repository "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

    echo "更新包列表..."
    sudo apt-get update

    echo "安裝 Docker..."
    sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

    echo "將當前用戶添加到 docker 群組..."
    sudo usermod -aG docker $USER

    echo "安裝 .NET 8 SDK..."
    wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh
    chmod +x ./dotnet-install.sh
    ./dotnet-install.sh --channel 8.0
    echo 'export DOTNET_ROOT=$HOME/.dotnet' >> $HOME/.bashrc
    echo 'export PATH=$PATH:$DOTNET_ROOT:$DOTNET_ROOT/tools' >> $HOME/.bashrc
    source $HOME/.bashrc

    echo "安裝 Node.js 20..."
    curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
    sudo apt-get install -y nodejs

    echo "安裝 Yarn..."
    sudo npm install -g yarn

    echo "安裝 Next.js..."
    sudo npm install -g next

    echo "設置 Corepack 和 Yarn..."
    sudo corepack enable
    corepack prepare yarn@4.4.1 --activate

    echo "驗證安裝..."
    $HOME/.dotnet/dotnet --version
    node --version
    yarn --version
    npx next --version

    echo "安裝完成。請登出並重新登入 vagrant 用戶,或重啟虛擬機以確保所有更改生效。"
  SHELL

  config.vm.provision "shell", run: "always", inline: <<-SHELL
    echo "每次啟動虛擬機時執行的腳本..."
    echo "確保 Docker 服務正在運行..."
    sudo systemctl start docker
    echo "Docker 服務狀態:"
    sudo systemctl status docker
  SHELL
end

啟動 Vagrant 環境

執行以下命令啟動 Vagrant 環境:

vagrant up

首次啟動可能需要一些時間,因為它需要下載基礎映像並安裝所有必要的軟體。

Windows 上的 Vagrant 安裝和配置

安裝必要軟體

在 Windows 上,我們需要安裝以下軟體:

  1. Vagrant
  2. VirtualBox(作為虛擬化提供者)

安裝 Vagrant

  1. 訪問 Vagrant 官方下載頁面
  2. 下載適用於 Windows 的安裝程式
  3. 執行安裝程式,按照提示完成安裝

安裝 VirtualBox

  1. 訪問 VirtualBox 下載頁面
  2. 下載適用於 Windows 的安裝程式
  3. 執行安裝程式,按照提示完成安裝

配置 Vagrant

  1. 打開命令提示符或 PowerShell

  2. 創建專案目錄:

mkdir vagrant-docker-env
cd vagrant-docker-env
  1. 初始化 Vagrant 配置檔案:
vagrant init
  1. 編輯 Vagrantfile,使用以下內容:
Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-20.04"

  config.vm.provider "virtualbox" do |vb|
    vb.memory = 2048
    vb.cpus = 2
  end

  config.vm.synced_folder ".", "/vagrant", type: "virtualbox"

  config.vm.network "forwarded_port", guest: 3000, host: 3001
  config.vm.network "forwarded_port", guest: 5000, host: 5001

  config.vm.provision "shell", privileged: false, inline: <<-SHELL
    set -e
    set -x

    echo "正在更新系統包..."
    sudo apt-get update
    sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common

    echo "添加 Docker 官方 GPG key..."
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

    echo "設置 Docker repository..."
    sudo add-apt-repository "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

    echo "更新包列表..."
    sudo apt-get update

    echo "安裝 Docker..."
    sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

    echo "將當前用戶添加到 docker 群組..."
    sudo usermod -aG docker $USER

    echo "安裝 .NET 8 SDK..."
    wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh
    chmod +x ./dotnet-install.sh
    ./dotnet-install.sh --channel 8.0
    echo 'export DOTNET_ROOT=$HOME/.dotnet' >> $HOME/.bashrc
    echo 'export PATH=$PATH:$DOTNET_ROOT:$DOTNET_ROOT/tools' >> $HOME/.bashrc
    source $HOME/.bashrc

    echo "安裝 Node.js 20..."
    curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
    sudo apt-get install -y nodejs

    echo "安裝 Yarn..."
    sudo npm install -g yarn

    echo "安裝 Next.js..."
    sudo npm install -g next

    echo "設置 Corepack 和 Yarn..."
    sudo corepack enable
    corepack prepare yarn@4.4.1 --activate

    echo "驗證安裝..."
    $HOME/.dotnet/dotnet --version
    node --version
    yarn --version
    npx next --version

    echo "安裝完成。請登出並重新登入 vagrant 用戶,或重啟虛擬機以確保所有更改生效。"
  SHELL

  config.vm.provision "shell", run: "always", inline: <<-SHELL
    echo "每次啟動虛擬機時執行的腳本..."
    echo "確保 Docker 服務正在運行..."
    sudo systemctl start docker
    echo "Docker 服務狀態:"
    sudo systemctl status docker
  SHELL
end

啟動 Vagrant 環境

在命令提示符或 PowerShell 中執行以下命令啟動 Vagrant 環境:

vagrant up

部署 front-nextjs 和 backend-dotnet Docker 映像

現在我們已經在 macOS 和 Windows 上設置了 Vagrant 環境,接下來我們將部署 front-nextjs 和 backend-dotnet 的 Docker 映像。

進入 Vagrant 環境

無論你使用的是 macOS 還是 Windows,都可以使用以下命令進入 Vagrant 環境:

vagrant ssh

部署 front-nextjs Docker 映像

  1. 進入專案目錄:
cd /vagrant/front-nextjs
  1. 創建 Dockerfile:
cat << EOF > Dockerfile
# 構建階段
FROM node:18-alpine AS builder

# 設置工作目錄
WORKDIR /app

# 複製 package.json 和 yarn.lock
COPY package.json yarn.lock ./

# 安裝依賴
RUN yarn install --frozen-lockfile

# 複製源代碼
COPY . .

# 構建應用
RUN yarn build

# 生產階段
FROM node:18-alpine AS runner

WORKDIR /app

# 從構建階段複製必要文件
COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

# 設置環境變量
ENV NODE_ENV production

# 暴露端口
EXPOSE 3000

# 啟動應用
CMD ["yarn", "start"]
EOF
  1. 構建 Docker 映像:
docker build -t front-nextjs .
  1. 運行 Docker 容器:
docker run -d -p 3000:3000 --name front-nextjs front-nextjs

部署 backend-dotnet Docker 映像

  1. 進入專案目錄:
cd /vagrant/backend-dotnet
  1. 創建 Dockerfile:
cat << EOF > Dockerfile
# 構建階段
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src

# 復制 csproj 並還原依賴項
COPY ["backend-dotnet.csproj", "./"]
RUN dotnet restore "backend-dotnet.csproj"

# 複製源代碼並構建
COPY . .
RUN dotnet build "backend-dotnet.csproj" -c Release -o /app/build

# 發布
FROM build AS publish
RUN dotnet publish "backend-dotnet.csproj" -c Release -o /app/publish

# 最終階段
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "backend-dotnet.dll"]
EOF
  1. 構建 Docker 映像:
docker build -t backend-dotnet .
  1. 運行 Docker 容器:
docker run -d -p 5000:80 --name backend-dotnet backend-dotnet

驗證部署

現在,你應該可以通過以下 URL 訪問你的應用:

  • front-nextjs: http://localhost:3001
  • backend-dotnet: http://localhost:5001

最佳實踐和注意事項

在使用 Vagrant 和 Docker 進行開發和部署時,以下是一些最佳實踐和需要注意的事項:

1. 版本控制

  • 將 Vagrantfile 和 Dockerfile 加入版本控制系統(如 Git)中。這樣可以確保團隊成員使用相同的環境配置。
  • 對於 .gitignore 文件,確保排除 .vagrant/ 目錄和其他不需要版本控制的文件。

2. 資源管理

  • 根據專案需求和主機性能調整虛擬機的記憶體和 CPU 配置。
  • 定期清理不再使用的 Docker 映像和容器,以節省磁碟空間。

3. 安全性

  • 不要在 Vagrantfile 或 Dockerfile 中硬編碼敏感資訊(如密碼或 API 金鑰)。使用環境變數或安全的密碼管理工具。
  • 定期更新基礎映像和依賴項,以修補潛在的安全漏洞。

4. 效能優化

  • 使用 Docker 的多階段構建來減小最終映像的大小。
  • 對於 front-nextjs,考慮使用靜態導出功能來提高性能。
  • 對於 backend-dotnet,確保在生產環境中啟用適當的優化設置。

5. 開發工作流程

  • 使用 Docker Compose 來管理多個相關的容器(例如,前端、後端和數據庫)。
  • 設置開發、測試和生產環境的不同配置文件。

6. 監控和日誌

  • 實施日誌記錄策略,確保可以輕鬆診斷問題。
  • 考慮使用監控工具來跟踪應用程序的性能和健康狀況。

常見問題及解決方案

在使用 Vagrant 和 Docker 進行開發時,你可能會遇到一些常見問題。以下是一些問題及其解決方案:

1. Vagrant 無法啟動虛擬機

問題:執行 vagrant up 時出現錯誤。

解決方案

  • 確保虛擬化軟體(VirtualBox 或 Parallels)正確安裝且版本兼容。
  • 檢查 BIOS 設置,確保啟用了虛擬化支持。
  • 嘗試使用 vagrant up --debug 來獲取更詳細的錯誤信息。

2. 無法訪問轉發的端口

問題:無法通過 localhost 訪問應用程序。

解決方案

  • 確保 Vagrantfile 中正確配置了端口轉發。
  • 檢查虛擬機內部的防火牆設置。
  • 使用 netstat -tuln 命令檢查端口是否正在監聽。

3. Docker 構建失敗

問題:執行 docker build 時出現錯誤。

解決方案

  • 檢查 Dockerfile 的語法錯誤。
  • 確保所有必要的文件都在構建上下文中。
  • 檢查網絡連接,確保可以下載所需的依賴項。

4. 容器啟動後立即退出

問題:使用 docker run 啟動容器後,容器立即停止。

解決方案

  • 檢查容器日誌以查找錯誤信息:docker logs <container_id>
  • 確保 Dockerfile 中指定了正確的啟動命令。
  • 檢查應用程序的配置,確保它可以在容器環境中正確運行。

5. 同步文件夾權限問題

問題:在主機和虛擬機之間同步文件時出現權限錯誤。

解決方案

  • 在 Vagrantfile 中調整同步文件夾的選項,例如:
config.vm.synced_folder ".", "/vagrant", owner: "vagrant", group: "vagrant"

config.bindfs.bind_folder 是 Vagrant 的 bindfs 插件提供的功能。Bindfs 是一個用於將一個目錄掛載到另一個位置的工具,它允許你在掛載時改變文件的所有者、組和權限。在 Vagrant 中使用 bindfs 可以解決許多與共享文件夾相關的權限問題。

以下是如何在 Vagrantfile 中使用 config.bindfs.bind_folder 的基本示例:

Vagrant.configure("2") do |config|
  # 其他配置...

  config.vm.synced_folder ".", "/vagrant", type: "nfs"
  
  config.bindfs.bind_folder "/vagrant", "/vagrant-bindfs",
    force_user:  'vagrant',
    force_group: 'vagrant',
    perms:       "u=rwX:g=rD:o=rD"

  # 其他配置...
end

在這個例子中:

  1. 首先,我們使用 NFS 將主機的當前目錄(".")同步到虛擬機的 “/vagrant” 目錄。

  2. 然後,我們使用 bindfs 將 “/vagrant” 目錄綁定到 “/vagrant-bindfs”。

  3. force_userforce_group 選項將所有文件的所有者和組設置為 ‘vagrant’。

  4. perms 選項設置文件權限:用戶有讀、寫和執行權限;組和其他用戶只有讀和執行權限。

使用 bindfs 的好處包括:

  1. 解決權限問題:可以確保虛擬機內的用戶有正確的文件訪問權限。

  2. 提高安全性:可以限制對共享文件的訪問。

  3. 靈活性:可以在不同的位置掛載相同的目錄,每個位置有不同的權限設置。

要使用這個功能,你需要安裝 vagrant-bindfs 插件:

vagrant plugin install vagrant-bindfs

然後,你可以修改你的 Vagrantfile 來包含 bindfs 配置。這裡是一個結合了之前的配置和 bindfs 的例子:

Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-20.04"

  config.vm.provider "parallels" do |prl|
    prl.memory = 2048
    prl.cpus = 2
  end

  config.vm.network "forwarded_port", guest: 3000, host: 3001
  config.vm.network "forwarded_port", guest: 5000, host: 5001

  config.vm.synced_folder ".", "/vagrant", type: "nfs"
  
  config.bindfs.bind_folder "/vagrant", "/home/vagrant/project",
    force_user:  'vagrant',
    force_group: 'vagrant',
    perms:       "u=rwX:g=rD:o=rD"

  # 其他配置保持不變...
end

這個配置會將 NFS 共享的 “/vagrant” 目錄綁定到 “/home/vagrant/project”,並給予 vagrant 用戶完全的訪問權限。

使用 bindfs 可以有效地解決許多與文件權限相關的問題,特別是在使用 NFS 或其他共享文件系統時。它為管理虛擬機中的文件權限提供了更大的靈活性和控制。

進階配置

對於更複雜的項目,你可能需要進行一些進階配置:

1. 使用 Docker Compose

為了更好地管理多個相關的容器,可以使用 Docker Compose。在專案根目錄創建一個 docker-compose.yml 文件:

version: '3'
services:
  frontend:
    build: ./front-nextjs
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - backend

  backend:
    build: ./backend-dotnet
    ports:
      - "5000:80"
    environment:
      - ASPNETCORE_ENVIRONMENT=Production

  database:
    image: postgres:13
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=myuser
      - POSTGRES_PASSWORD=mypassword

這樣,你可以使用 docker-compose up 命令一次性啟動所有服務。

2. 配置持續集成/持續部署 (CI/CD)

考慮設置 CI/CD 流程,以自動化測試和部署過程。這可以使用 GitLab CI/CD、Jenkins 或 GitHub Actions 等工具實現。

3. 使用環境變量

為了提高安全性和靈活性,使用環境變量來配置應用程序。可以在 Dockerfile 或 docker-compose.yml 文件中定義這些變量。

結論

使用 Vagrant 和 Docker 來部署 front-nextjs 和 backend-dotnet 應用可以極大地簡化開發流程,確保所有團隊成員在一致的環境中工作。通過遵循本文提供的步驟和最佳實踐,你可以建立一個穩定、可重複的開發環境,無論是在 macOS 還是 Windows 系統上。

記住,環境配置是一個持續的過程。隨著項目的發展,你可能需要調整配置以滿足新的需求。定期檢視和更新你的 Vagrant 和 Docker 配置,以確保它們繼續滿足團隊的需求。

最後,鼓勵團隊成員分享他們的經驗和發現的任何問題。通過持續的溝通和改進,你可以不斷優化開發環境,提高團隊的生產力和代碼質量。

延伸閱讀

為了進一步深入了解本文涉及的技術,以下是一些推薦的資源:

  1. Vagrant 官方文檔
  2. Docker 官方文檔
  3. Next.js 官方文檔
  4. .NET 官方文檔
  5. Docker Compose 官方文檔

通過學習這些資源,你可以更好地理解和利用這些工具,為你的開發流程帶來更多的效率和靈活性。