2024-10-13|閱讀時間 ‧ 約 0 分鐘

D5 - 拆解 Docker 環境:快速理解Nginx 反向代理 Nuxt 和 Laravel 的關係

好了,到了這一步,我們已經有了一個基於 Docker 的開發環境,但你可能會想:「這麼多配置,到底是怎麼運作的?」別擔心,今天我們要一起拆解這個 Docker 環境,深入了解 Nginx 如何作為反向代理,協調 Nuxt(前端)和 Laravel(後端)之間的關係。

Docker 環境架構的整體說明

首先,讓我們快速回顧一下整個 Docker 環境的架構:

  • Laravel (backend):後端 API 服務,使用 PHP-FPM 運行。
  • Nuxt (frontend):前端應用,使用 NodeJS 運行,作為 Vue 的服務端渲染框架。
  • Nginx:作為反向代理,處理來自瀏覽器的請求,並將它們分別轉發給 Nuxt 和 Laravel。
  • MariaDB:資料庫服務,用於存儲 Laravel API 的數據。
    我們使用了 Docker Compose 來定義這些容器,讓它們在同一個網路下協同工作。現在,讓我們深入了解每個部分的設定,並探討為什麼要這麼做。

一、docker-compose.yml:容器協調的大腦

docker-compose.yml 是整個 Docker 環境的核心,負責協調各個服務。我們來逐段解析這個檔案,了解每個設定的目的。

version: '3.8'

services:
# Laravel (backend)
backend:
build:
dockerfile: ./.docker-env/api/Dockerfile
container_name: laravel-app
restart: on-failure
volumes:
- ./api:/var/www/html
environment:
- APP_ENV=local
- APP_DEBUG=true
- DB_CONNECTION=mysql
- DB_HOST=db
- DB_PORT=3306
- DB_DATABASE=finance
- DB_USERNAME=root
- DB_PASSWORD=root
command: bash -c "if [ ! -f composer.json ]; then composer create-project --prefer-dist laravel/laravel .; fi && composer install && php-fpm"
depends_on:
- db
networks:
- app-network

為什麼這麼設定?

  • build:指定 Dockerfile 的路徑,構建 Laravel 的容器環境。
  • volumes:將本機的 ./api 目錄掛載到容器內的 /var/www/html,方便我們在本機編輯代碼,容器即時更新。
  • environment:設定 Laravel 環境變數,特別是資料庫的連線資訊,讓 Laravel 知道該連接到哪個資料庫。
  • command:這裡有點技巧,我們在容器啟動時檢查 composer.json 是否存在,沒有的話就創建一個新的 Laravel 專案。接著安裝依賴並啟動 PHP-FPM。
  • depends_on:確保在啟動 backend 服務前,資料庫服務 db 已經啟動。
  • networks:將服務加入同一個網路,方便容器之間的通訊。

小提醒

別忘了:環境變數中的資料庫資訊要與資料庫服務的設定相匹配,否則 Laravel 可是會鬧脾氣的。

二、Dockerfile:打造專屬的容器環境

1. Laravel 的 Dockerfile

位於 .docker-env/api/Dockerfile,這個檔案定義了 Laravel 容器的環境。

# 使用 PHP 基礎映像檔
FROM php:8.2-fpm

# 安裝必要的系統套件和 PHP 擴展
RUN apt-get update && apt-get install -y \
git \
unzip \
libjpeg-dev \
libpng-dev \
libzip-dev \
&& docker-php-ext-install pdo_mysql zip

# 安裝 Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# 設定工作目錄
WORKDIR /var/www/html

# 複製專案檔案
COPY ../../api .

# 設置權限
RUN chown -R www-data:www-data /var/www/html

# Expose port and start PHP-FPM
EXPOSE 9000
CMD ["php-fpm"]

為什麼這麼設定?

  • FROM php:8.2-fpm:使用官方的 PHP 8.2 FPM 映像作為基礎,為什麼?因為 Laravel 需要 PHP 環境,而 FPM 能夠與 Nginx 整合。
  • 安裝系統套件和 PHP 擴展:Laravel 依賴於一些 PHP 擴展,如 pdo_mysql、zip 等,沒有它們,某些功能會無法運作。
  • 安裝 Composer:Composer 是 PHP 的套件管理工具,Laravel 的依賴都透過它來管理。
  • 設定工作目錄:將工作目錄設為 /var/www/html,這是 Nginx 預設的網頁根目錄。
  • COPY 專案檔案:將我們的 Laravel 專案代碼複製到容器內。
  • 設置權限:確保網頁服務有權限讀取和寫入必要的檔案。
  • CMD ["php-fpm"]:啟動 PHP-FPM 服務。

個人經驗分享

小技巧:有時候忘記安裝某個 PHP 擴展,結果功能跑不起來,那種感覺就像買了新電器卻沒電池。所以,提前確認所需的擴展,能省下不少時間。

2. Nuxt 的 Dockerfile

位於 .docker-env/web/Dockerfile,定義了 Nuxt 容器的環境。

# 使用 Node.js 20 映像
FROM node:20-alpine

# 設定工作目錄
WORKDIR /app

# 複製 package.json
COPY package*.json ./

# 暴露端口
EXPOSE 3000

# 啟動命令將在 docker-compose.yml 中定義

為什麼這麼設定?

  • FROM node:20-alpine:使用輕量級的 Node.js 20 Alpine 映像,節省空間和資源。
  • WORKDIR /app:設置工作目錄為 /app。
  • COPY package.json ./*:將 package.json 複製進去,方便後續安裝依賴。
  • EXPOSE 3000:暴露 Nuxt 預設的 3000 端口。

三、Nginx 配置:反向代理的魔法師

Nginx 作為反向代理,負責將不同的請求導向正確的服務。我們需要兩個配置檔案:api.conf 和 web.conf。

1. Laravel 的 Nginx 配置 (api.conf)

server {
listen 80;
server_name api.localhost;
root /var/www/html/public;
index index.php index.html;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php$ {
include fastcgi_params;
fastcgi_pass laravel-app:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

location ~ /\.ht {
deny all;
}
}

為什麼這麼設定?

  • server_name api.localhost:指定服務的域名,方便本地開發時區分前後端。
  • root /var/www/html/public:Laravel 的入口位於 public 資料夾。
  • location /:處理所有請求,使用 try_files 嘗試找到對應的檔案,否則轉到 index.php。
  • location ~ .php$:處理 PHP 檔案的請求,透過 FastCGI 傳遞給 PHP-FPM(laravel-app:9000)。

2. Nuxt 的 Nginx 配置 (web.conf)

server {
listen 80;
server_name web.localhost;

location / {
proxy_pass http://nuxt-app:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}

為什麼這麼設定?

  • server_name web.localhost:指定前端服務的域名。
  • proxy_pass http://nuxt-app:3000:將所有請求代理到 Nuxt 應用的容器。
  • proxy_set_header:設定必要的頭資訊,確保 WebSocket 等功能正常運作。

小故事時間

曾經有一次,我忘了在 Nginx 配置中設定 proxy_set_header,結果 WebSocket 連線一直失敗。那種抓不到 bug 的感覺,真的是讓人懷疑人生。所以,細節真的很重要!

四、MariaDB:資料庫的心臟

在 docker-compose.yml 中,MariaDB 的配置如下:

# MySQL (MariaDB)
db:
image: mariadb:latest
container_name: mariadb
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: finance
MYSQL_USER: root
MYSQL_PASSWORD: root
volumes:
- "./.docker-env/.db_data/mysql:/var/lib/mysql"
networks:
- app-network

為什麼這麼設定?

  • image: mariadb:latest:使用最新的 MariaDB 映像,提供 MySQL 兼容的資料庫服務。
  • environment:設定資料庫的初始用戶名、密碼和資料庫名稱。
  • volumes:將資料庫資料持久化到本機,避免容器重啟時數據丟失。
  • networks:加入同一個網路,讓 Laravel 可以連接到資料庫。

驗證資料庫連線

要確認 Laravel 是否成功連接到資料庫,可以在容器中執行遷移命令:

docker-compose exec backend php artisan migrate

如果看到遷移成功的訊息,表示 Laravel 與資料庫的連線正常。

五、Docker 指令小抄

以下是一些常用的 Docker 指令,方便你在開發過程中操作:

  • 啟動所有服務:
docker-compose up -d --build
  • 查看容器日誌:
docker-compose logs -f [service_name]
  • 進入容器終端:
docker-compose exec [service_name] bash
  • 重新啟動服務:
docker-compose restart [service_name]
  • 停止並移除容器:
docker-compose down

六、為什麼要這樣架構?

  • Docker 的好處:透過容器化,我們可以確保在任何環境下都能有一致的開發和部署環境,再也不用擔心「在我電腦上可以跑啊!」的問題。
  • Nginx 反向代理:統一管理請求,未來要加入 HTTPS、負載均衡等功能都更方便。
  • 服務解耦:前端、後端、資料庫各自獨立,方便維護和升級。

小結

恭喜你!我們已經深入了解了整個 Docker 環境的架構和配置。現在,你不僅知道「怎麼做」,還了解了「為什麼要這麼做」。這種理解將讓你在未來的開發中更加游刃有餘。

最後的叮嚀

別害怕嘗試和錯誤,有時候問題的解答就藏在那些看似不起眼的細節中。就像我常說的,「調整了 N 個配置,只為了解決一個小問題,但這就是成長的過程」。

接下來,我們將進行第一階驗收,看看這一切是否如我們預期的那樣順利運行!

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.