告別單機作戰!Docker Compose 終極交響樂:一鍵指揮 WordPress + Nginx + Redis + MariaDB 四重奏

2025/11/29 | WP 開發技巧, 全端與程式開發, 技術教學資源, 架構與效能優化

告別單機作戰!Docker Compose 終極交響樂:一鍵指揮 WordPress + Nginx + Redis + MariaDB 四重奏

哈囉,我是浪花科技的資深工程師 Eric。如果你還記得,我們之前聊過如何用 Docker 把 WordPress 包起來,解決了那句工程師最痛恨的魔咒:「在我電腦明明可以跑的啊?」。但說真的,那只是前菜。一個真正能打仗、扛得住流量的專業網站,絕對不是只有 WordPress 本體那麼單純。它更像一個交響樂團,需要網頁伺服器、資料庫、快取系統… 各司其職,完美協奏。

今天,我們就要來談談如何從一個單純的樂手,晉升為整個樂團的指揮家。我們要用的指揮棒,就是 Docker Compose。這篇文章會帶你從零開始,用一個 `docker-compose.yml` 檔案,一鍵啟動一個包含 Nginx、MariaDB、Redis 與 WordPress (PHP-FPM) 的高效能網站架構。別再手動一個一個安裝服務了,身為一個追求效率(跟懶惰)的工程師,自動化才是王道!

為什麼單一容器不夠?解構現代 WordPress 網站架構

在我們動手之前,先來個小小的精神喊話,或者說是工程師的囉嗦。為什麼我們需要這麼多服務?不能全部塞在一個 Docker 容器裡嗎?理論上可以,但那就像把小提琴手、鼓手、鋼琴師全塞在一個電話亭裡,不僅施展不開,還很容易因為一個人出錯(比如資料庫掛了)導致整個樂團(網站)跟著陪葬。

一個專業的 WordPress 網站架構,通常包含以下幾個核心角色:

  • 網頁伺服器 (Web Server) – Nginx: 樂團的門面擔當。它負責接收來自使用者的所有請求,把靜態檔案(如圖片、CSS、JS)直接回傳,並將動態請求(需要 PHP 處理的頁面)轉交給後端的 PHP-FPM。
  • PHP 處理器 (PHP-FPM): 樂團的主唱。這是 WordPress 的核心,負責執行所有 PHP 程式碼,從資料庫撈取資料,產生最終的 HTML 頁面。
  • 資料庫 (Database) – MariaDB: 樂團的靈魂與記憶庫。你的所有文章、頁面、使用者資料、設定… 全部都儲存在這裡。MariaDB 是 MySQL 的一個開源分支,完全相容且效能優異。
  • 物件快取 (Object Cache) – Redis: 樂團的加速器。每次頁面載入都去資料庫重新查詢太慢了。Redis 是一個基於記憶體的快取系統,可以將常用的查詢結果暫存在記憶體中,大幅減少資料庫的壓力,讓網站快到飛起。

透過 Docker Compose 多服務部署,我們可以將這四個角色分別放進獨立的容器中。它們各自獨立、互不干擾,卻又能透過 Docker 內建的虛擬網路高效溝通。這就是所謂的「關注點分離」,不僅維護方便,未來要針對某個服務(例如資料庫)單獨升級或擴展也輕而易舉。

Docker Compose 核心概念:服務、網路與卷宗

Docker Compose 的精髓全在一支名為 `docker-compose.yml` 的 YAML 格式設定檔。你可以把它想像成樂團的總樂譜,上面清楚標示了每個樂手(服務)該做什麼、用什麼樂器(映像檔)、以及他們之間如何溝通(網路)。

  • 服務 (Services): 樂譜中的每個獨立部分。在我們的例子中,`nginx`、`wordpress`、`db`、`redis` 就是四個獨立的服務。
  • 網路 (Networks): Docker Compose 會自動幫你建立一個專屬的內部虛擬網路,讓所有服務可以透過「服務名稱」直接溝通。例如,WordPress 容器可以直接用 `db` 這個主機名稱連到 MariaDB 容器,完全不用管它實際的 IP 是多少,超方便!而且這個網路是隔離的,你不用把資料庫的 3306 連接埠暴露在公網上,大大提升了安全性。
  • 卷宗 (Volumes): 容器本身是「無狀態」的,意思是只要容器一刪除,裡面的資料就灰飛煙滅了。這對程式碼來說沒問題,但對資料庫或使用者上傳的檔案來說可是天大的災難。卷宗 (Volume) 就是用來解決這個問題的,它能將主機的某個資料夾掛載到容器內部,讓資料可以永久保存,即使容器被銷毀重建,資料依然安然無恙。

實戰演練:打造你的 WordPress 高效能四重奏

理論說完了,來點實際的吧!跟著我一步一步把這個高效能架構建立起來。

Step 1: 建立專案結構

首先,在你的電腦上建立一個專案資料夾,結構如下:


my-wordpress-stack/
├── docker-compose.yml
├── nginx/
│   └── default.conf
└── wordpress/
    └── (這個資料夾會自動產生,用來存放 WordPress 核心檔案)

Step 2: 編寫指揮棒 `docker-compose.yml`

這就是我們整個架構的核心,請將以下內容貼到 `docker-compose.yml` 檔案中。我會逐段解釋每個設定的意義。


version: '3.8'

services:
  db:
    image: mariadb:10.6
    container_name: my_wp_db
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: your_strong_root_password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: your_strong_user_password
    networks:
      - wordpress_network

  redis:
    image: redis:6.2-alpine
    container_name: my_wp_redis
    restart: unless-stopped
    networks:
      - wordpress_network

  wordpress:
    image: wordpress:6.4-php8.1-fpm-alpine
    container_name: my_wp_app
    restart: unless-stopped
    depends_on:
      - db
      - redis
    volumes:
      - ./wordpress:/var/www/html
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: your_strong_user_password
      WORDPRESS_DB_NAME: wordpress
    networks:
      - wordpress_network

  nginx:
    image: nginx:1.25-alpine
    container_name: my_wp_nginx
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./wordpress:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - wordpress
    networks:
      - wordpress_network

volumes:
  db_data:

networks:
  wordpress_network:
    driver: bridge

稍微囉嗦一下各區塊的設定:

  • db 服務:使用 MariaDB 10.6 映像檔。volumes: - db_data:/var/lib/mysql 這行是關鍵,它建立了一個名為 `db_data` 的具名卷宗 (named volume),專門用來存放資料庫檔案。`environment` 則是用來設定資料庫的各種帳號密碼。
  • redis 服務:相對單純,就是啟動一個 Redis 容器。
  • wordpress 服務:我們用的是 `fpm-alpine` 版本的映像檔,它只包含 PHP-FPM,不含網頁伺服器,更輕量、更專業。depends_on 確保它會在 `db` 和 `redis` 啟動之後才啟動。volumes: - ./wordpress:/var/www/html 則是將我們主機的 `wordpress` 資料夾掛載進去,這樣我們就能直接在主機上修改佈景主題或外掛檔案了。
  • nginx 服務:負責對外。ports: - "8080:80" 把容器的 80 port 映射到我們主機的 8080 port,這樣我們就能透過 `http://localhost:8080` 訪問網站。它同時掛載了 WordPress 的檔案目錄和我們自訂的 Nginx 設定檔。

Step 3: Nginx 設定檔 (`nginx/default.conf`)

Nginx 需要知道如何處理 PHP 請求。將以下內容貼到 `nginx/default.conf`:


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

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

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass wordpress:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

這裡的魔法是 fastcgi_pass wordpress:9000;。它告訴 Nginx,把所有 PHP 請求都轉發給一個叫做 `wordpress` 的主機的 9000 port,而這個 `wordpress` 正是我們在 `docker-compose.yml` 裡定義的服務名稱!這就是 Docker Compose 內建 DNS 解析的威力。想了解更多 Nginx 的調校技巧,可以參考這篇 Nginx 效能調校聖經

Step 4: 啟動!`docker-compose up -d`

萬事俱備!在你的專案根目錄下,打開終端機,執行以下指令:

docker-compose up -d

-d 參數代表在背景執行。Docker Compose 會開始下載映像檔、建立網路、卷宗並依序啟動所有容器。你可以用 docker-compose ps 來查看所有容器的狀態。第一次啟動需要幾分鐘,請耐心等候。

啟動成功後,打開瀏覽器訪問 `http://localhost:8080`,你應該就能看到熟悉的 WordPress 安裝畫面了!

整合 Redis 物件快取:讓你的 WordPress 飛起來

我們的 Redis 容器已經在背景默默運作了,但 WordPress 還不知道它的存在。我們需要搭起他們之間的橋樑。

  1. 安裝 Redis 外掛: 進入 WordPress 後台,安裝並啟用「Redis Object Cache」這個外掛。
  2. 設定 `wp-config.php`: 啟用外掛後,它可能會提示 `wp-config.php` 無法寫入。沒關係,我們手動來。打開 `./wordpress/wp-config.php` 檔案 (如果還沒有,可以先完成 WordPress 安裝讓它自動生成),在 `/* That’s all, stop editing! Happy publishing. */` 這行註解之前,加入以下設定:
    
    define('WP_REDIS_HOST', 'redis');
    define('WP_REDIS_PORT', 6379);
    define('WP_CACHE_KEY_PREFIX', 'my_wp_site:');
    define('WP_CACHE', true);
    
  3. 啟用物件快取: 回到後台的 Redis Object Cache 設定頁面,點擊「Enable Object Cache」。如果狀態顯示為「Connected」,恭喜你!你的 WordPress 已經裝上了 Redis 渦輪引擎!想深入了解 Redis 如何為 WordPress 加速,可以看看這篇 Redis 物件快取實戰教學

工程師的囉嗦時間:常見陷阱與最佳實踐

踩過坑的學長告訴你,光是能跑起來還不夠,有幾個細節能讓你的開發流程更順暢、更安全。

檔案權限問題

Docker for Mac/Windows 通常處理得比較好,但在 Linux 上,你可能會遇到 Nginx 或 WordPress 因為權限不足而無法寫入 `./wordpress` 資料夾的問題。這是因為容器內的使用者 ID (UID) 和主機上的使用者 ID 不匹配。一個常見的解法是,在啟動容器後,手動修改主機上資料夾的權限,例如 sudo chown -R www-data:www-data wordpress/,但這不是最優雅的方式。更進階的作法是在 Dockerfile 中去動態設定使用者 ID,但這對初學者來說有點複雜,我們先知道有這個問題即可。

環境變數管理

直接把資料庫密碼寫在 `docker-compose.yml` 裡不是個好習慣,尤其當你要把這個檔案交給同事或上傳到 Git 時。最佳實踐是使用 `.env` 檔案。你可以在 `docker-compose.yml` 同層目錄下建立一個 `.env` 檔案,內容如下:


DB_ROOT_PASSWORD=your_strong_root_password
DB_USER=wordpress
DB_PASSWORD=your_strong_user_password
DB_NAME=wordpress

然後修改 `docker-compose.yml`,用 ${VARIABLE_NAME} 的語法來讀取:


# ...
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
# ...

這樣一來,你的敏感資訊就跟設定檔分開了,記得把 `.env` 加入到 `.gitignore` 中!

結論:你已經是半個 DevOps 工程師了!

恭喜你!你不再只是一個會用 WordPress 的開發者,你已經掌握了如何用 Docker Compose 這個強大的工具,來編排和管理一個現代化的、高效能的、可複製的網站應用程式架構。從今天起,無論是建立一個新的本地開發環境,還是要將整個專案打包交給同事,都只是一行 `docker-compose up -d` 的事。

這套架構不僅適用於開發,稍作調整(例如加入 SSL 憑證管理、更完善的備份策略),它完全有能力成為你正式上線網站的基石。這就是容器化帶來的革命:它模糊了開發與維運的界線,讓開發者能更好地掌控自己的應用程式。


延伸閱讀

打造一個穩固又高效的網站架構是專案成功的基礎。如果你在部署過程中遇到任何問題,或是希望為你的企業導入更專業、更客製化的 DevOps 流程與網站架構,浪花科技的團隊擁有豐富的實戰經驗。我們不只是寫程式,更是你數位轉型路上的技術夥伴。

別讓複雜的技術問題拖慢你的腳步,立即聯繫我們,讓我們的專業團隊為你量身打造最適合的解決方案!

常見問題 (FAQ)

Q1: Docker Compose 和單純的 Docker 指令有什麼不同?

A: 單純的 `docker run` 指令一次只能啟動和管理一個容器,當你需要啟動多個互相關聯的容器(如 Nginx, WordPress, DB)時,指令會變得非常冗長且難以管理。Docker Compose 則允許你用一個 YAML 設定檔來定義和管理整個應用程式的所有服務,只需一個 `docker-compose up` 指令就能啟動所有服務、設定好網路,讓整個流程變得極度簡潔、可重複且容易版本控制。

Q2: 我的 WordPress 容器連不上資料庫,顯示「Error establishing a database connection」,怎麼辦?

A: 這通常是網路或設定問題。請檢查以下幾點:
1. 服務名稱是否正確: 在 `docker-compose.yml` 中,WordPress 的 `WORDPRESS_DB_HOST` 環境變數值是否設定為資料庫服務的名稱(例如 `db:3306`)?
2. 網路設定: 確認 WordPress 容器和資料庫容器是否都加入了同一個 `networks`。
3. `depends_on`: 確認 WordPress 服務有設定 `depends_on: – db`,確保資料庫先於 WordPress 啟動。
4. 帳號密碼: 再三確認 `WORDPRESS_DB_USER`, `WORDPRESS_DB_PASSWORD`, `WORDPRESS_DB_NAME` 的值與資料庫服務中 `MYSQL_USER`, `MYSQL_PASSWORD`, `MYSQL_DATABASE` 的值完全一致。

Q3: 我需要為每個 WordPress 專案都建立一個這麼複雜的 `docker-compose.yml` 嗎?

A: 是的,這是最佳實踐。為每個專案建立獨立的 Docker Compose 環境可以確保專案之間的完全隔離,避免版本衝突(例如一個專案需要 PHP 8.1,另一個需要 PHP 7.4)或資料干擾。你可以將這份 `docker-compose.yml` 當作一個標準範本,每次有新專案時,複製一份並根據需求稍作修改(例如更改容器名稱、連接埠映射),這樣可以大大加速新專案的啟動流程。

Q4: 這種架構適合正式上線的生產環境 (Production) 嗎?

A: 絕對適合,但還需要一些強化。本文提供的架構是一個絕佳的起點。要投入生產環境,你還需要考慮:
1. SSL/HTTPS: 整合 Let’s Encrypt 或其他 SSL 憑證來啟用 HTTPS。
2. 安全性: 強化密碼策略、設定防火牆規則、定期更新映像檔版本。
3. 備份與還原: 建立定期的資料庫和檔案卷宗備份機制。
4. 監控與日誌: 整合日誌管理系統(如 ELK Stack)和監控工具(如 Prometheus/Grafana)來追蹤系統健康狀況。但其核心的多服務容器化理念,正是現代雲端應用部署的主流方式。

 
立即諮詢,索取免費1年網站保固