Day: November 8, 2025

  • Docker 中的 WordPress

    2018年的時候我就說要容器化了,但是一直沒有做這件事情,最主要的原因是我一直使用FreeBSD 而不是很愛用Linux,這幾天終於完整的把既有環境遷入了docker container,遇到的問題主要有這樣幾個:

    1)一些必要的 php-fpm modules 需使用dockerfile compile,這可能會花費一些時間,在第一次運行時。
    2)因為我使用php.sock,so both containers need to access /tmp or wherever you put the php.sock,如果您使用port 9000,那就更簡單一些。
    3)php-fpm和nginx 的配置文件中需要修改對應的run as user,因為目前大多數的docker images 是使用debian 系統構建的,所以需要修改為www-data user 才不會有file permission 的問題,同時host 上的文件權限也要對應,如何對應呢? 不要費勁去找什麼uid,docker exec -it nginx bash 然後chown -R www-data:www-data /home/www。
    4)systemd 啟動文件要手動加一個。
    5)wordpress 的wp-config.php 中需要將database host 修改為container name mysql-server,以及 redis object cache 的redis host 需要將其修改為redis 或者valkey container name。
    6)php.ini 中如果有使用redis 存儲session 的話,也需要將其修改為redis 或者valkey。

    看起來docker 應該在debian 或者ubuntu 上運行是最好的,因為container 內的app 如果需要讀寫host 的文件,通常他們的OS level user 是很容易對齊的,當然,對於那些不需要讀寫host 的micro services 來說,就沒有任何區別。

    ——

    docker-compose.yaml

    ——

    services:
      mysql:
        image: mysql:8.4
        container_name: mysql-server
        restart: always
        ports:
          - "3306:3306"
        environment:
          - TZ=Asia/Taipei
          - MYSQL_ROOT_PASSWORD=password
        volumes:
          - /var/lib/mysql:/var/lib/mysql
          - /etc/my.cnf:/etc/my.cnf
      memcached:
        image: memcached:latest
        container_name: memcached
        restart: always
        ports:
          - "11211:11211"
        command: ["memcached", "-m", "8"]
      redis:
        image: redis:latest
        container_name: redis
        restart: always
        ports:
          - "6379:6379"
        command: redis-server --maxmemory 8mb --maxmemory-policy allkeys-lru
      valkey:
        image: valkey/valkey:latest
        container_name: valkey
        restart: always
        ports:
          - "6380:6379"
        environment:
          - VALKEY_EXTRA_FLAGS=--maxmemory 8mb --maxmemory-policy allkeys-lru
      redisinsight:
        image: redis/redisinsight:latest
        container_name: redisinsight
        restart: always
        ports:
          - "5540:5540"
        environment:
          - TZ=Asia/Taipei
        volumes:
          - /home/ec2-user/redis-insight:/data
      nginx:
        image: nginx:latest
        container_name: nginx
        restart: always
        ports:
          - "80:80"
          - "443:443"
          - "3000:3000"
        volumes:
          - /etc/nginx:/etc/nginx:ro
          - /home/www:/home/www
          - /tmp:/tmp
        environment:
          - TZ=Asia/Taipei
      php-fpm:
        build: .
        container_name: php-fpm
        restart: always
        volumes:
          - /home/www:/home/www
          - /etc/php/php.ini:/usr/local/etc/php/php.ini
          - /etc/php/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf
          - /etc/php/php-fpm.d/zz-docker.conf:/usr/local/etc/php-fpm.d/zz-docker.conf
          - /tmp:/tmp
        environment:
          - TZ=Asia/Taipei
    # zabbix-server:
    #   image: zabbix/zabbix-server-mysql:latest
    #   container_name: zabbix-server
    #   restart: always
    #   ports:
    #     - "10051:10051"
    #   environment:
    #     - TZ=Asia/Taipei
    #     - ZBX_HOSTNAME=zabbix-server
    #     - DB_SERVER_HOST=database-mysql.ap-northeast.rds.amazonaws.com
    #     - DB_SERVER_PORT=3306
    #     - MYSQL_DATABASE=zabbix
    #     - MYSQL_PASSWORD=zabbix
    #     - MYSQL_USER=zabbix
    # zabbix-web:
    #   image: zabbix/zabbix-web-nginx-mysql:latest
    #   container_name: zabbix-web
    #   restart: always
    #   ports:
    #     - "8080:8080"
    #   environment:
    #     - TZ=Asia/Taipei
    #     - PHP_TZ=Asia/Taipei
    #     - ZBX_HOSTNAME=zabbix-web
    #     - ZBX_SERVER_HOST=zabbix-server
    #     - DB_SERVER_HOST=database-mysql.ap-northeast.rds.amazonaws.com
    #     - DB_SERVER_PORT=3306
    #     - MYSQL_DATABASE=zabbix
    #     - MYSQL_PASSWORD=zabbix
    #     - MYSQL_USER=zabbix
    # zabbix-agent:
    #   image: zabbix/zabbix-agent2:latest
    #   container_name: zabbix-agent
    #   restart: always
    #   privileged: true
    #   ports:
    #   - "10050:10050"
    #   pid: host
    #   volumes:
    #     - /proc:/host/proc:ro
    #     - /sys:/host/sys:ro
    #     - /dev:/host/dev:ro
    #     - /:/host/root:ro
    #   environment:
    #     - TZ=Asia/Taipei
    #     - ZBX_HOSTNAME=Zabbix server
    #     - ZBX_SERVER_HOST=zabbix-server
    #     - ZBX_SERVERACTIVE=zabbix-server:10051
    #     - ZBX_LISTENIP=0.0.0.0
    # n8n:
    #   image: docker.n8n.io/n8nio/n8n
    #   container_name: n8n
    #   restart: always
    #   ports:
    #     - "5678:5678"
    #   environment:
    #     - TZ=Asia/Taipei
    #     - N8N_SECURE_COOKIE=false
    #     - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
    #   volumes:
    #     - /home/ec2-user/n8ndata:/home/node/.n8n

    ——

    cat dockerfile

    ——

    FROM php:fpm
    RUN apt-get update && apt-get install -y \
        libfreetype6-dev \
        libjpeg62-turbo-dev \
        libpng-dev \
        libzip-dev \
        libicu-dev \
        libmagickwand-dev \
        libgmp-dev \
        libxslt1-dev \
        libbz2-dev \
        libcurl4-openssl-dev \
        libxml2-dev \
        libsqlite3-dev \
        && rm -rf /var/lib/apt/lists/*
    RUN docker-php-ext-configure gd --with-freetype --with-jpeg
    RUN docker-php-ext-install -j$(nproc) \
        bz2 calendar ctype curl dom exif fileinfo filter ftp gd gettext gmp \
        intl mysqli opcache pcntl pdo pdo_mysql pdo_sqlite posix session \
        shmop sockets sysvmsg sysvsem sysvshm xml xmlreader xmlwriter xsl zip
    RUN pecl install redis igbinary msgpack imagick \
        && docker-php-ext-enable redis igbinary msgpack imagick

    ——

    cat run-docker.sh

    ——

    docker-compose down
    sleep 2
    docker-compose pull
    docker-compose up -d --force-recreate

    cat /etc/systemd/system/docker-compose-app.service

    [Unit]
    Description=Docker Compose Application Service
    Requires=docker.service
    After=docker.service
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    WorkingDirectory=/root
    ExecStart=/usr/local/bin/docker-compose up -d
    ExecStop=/usr/local/bin/docker-compose down
    TimeoutStartSec=0
    [Install]
    WantedBy=multi-user.target

    ——

    cat nginx.conf | grep www-data

    ——

    user    www-data;

    ——

    cat php-fpm.d/www.conf |grep www-data

    ——

    user = www-data
    group = www-data
    listen.owner = www-data
    listen.group = www-data

    ——

    wordpress wp-config.php

    ——

    define('WP_REDIS_HOST', 'valkey');
    ...
    define('DB_HOST', 'mysql-server');

    但是完成之後,我並沒有想要遷移到Docker ,這種管理一致性對於單個節點的blog 來說並沒有帶來多大的好處。

    因為在現代的FreeBSD(以前的不行,repo 裡面的software 都too old)上可以定時pkg upgrade 以達成升級到最新版本組件的目的,而大多數Linux 可以通過dnf-automatic 來自動升級。

    一個適用的場景應該是,每一個網站使用不同的容器,可以進行彼此的隔離,還可以對容器的資源使用進行限制,非常適合大家共享一台主機資源的時候。

    或者是,多個服務組件在不同的host 上分別部署,互相作為cluster 的節點,只有在cluster 的架構上,才會展現出優勢。