iT邦幫忙

2024 iThome 鐵人賽

DAY 5
0
Software Development

我獨自開發 - 30天進化之路,掌握 Laravel + Nuxt系列 第 5

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

  • 分享至 

  • xImage
  •  

好了,到了這一步,我們已經有了一個基於 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 個配置,只為了解決一個小問題,但這就是成長的過程」。

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


上一篇
D4 - 來吧!用 Docker 打造開發環境(Laravel + Nuxt + Nginx + MariaDB)
下一篇
D6 - 第一階段小驗收
系列文
我獨自開發 - 30天進化之路,掌握 Laravel + Nuxt13
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言