↓ До тексту
  1. Статті/

WordPress у Docker: той самий стек, але в контейнерах

·5 хвилин
cat /etc/passwd
Автор
cat /etc/passwd
Технічний блог про Linux, DevOps та Open Source технології.
Зміст
WordPress по-дорослому - частина серії статей.
Частина 2: ця стаття (ти тут)

Нещодавно ми зібрали WordPress руками, по-дорослому - Apache з PHP-FPM, MariaDB з окремим юзером, Redis object cache. Корисно, бо розумієш, що з чого складається. Але щодня так ніхто не робить: у проді той самий стек живе в контейнерах. Коли знаєш, що всередині, docker compose перестає бути магією - це просто зручна упаковка тих самих чотирьох речей. Зберемо її.

Що потрібно зробити?
#

Підняти той самий стек - WordPress, база, кеш - але одним compose.yml: три сервіси (wordpress, mariadb, redis), дані в іменованих volume, база з healthcheck, Redis як object cache. Плюс wp-cli окремим one-off сервісом, щоб ставити плагіни й робити install, не лізучи в контейнер руками.

З чим працюю?
#

1
2
3
root@wpdk:~# cat /etc/os-release
PRETTY_NAME="Ubuntu 26.04 LTS"
VERSION_CODENAME=resolute

Цього разу - Ubuntu 26.04 (щоб показати, що стек від дистрибутива не залежить: Docker є Docker). Передумова одна: Docker уже стоїть. Якщо ще ні - як поставити його по-людськи з офіційного репо, я показував окремо: Docker на свіжому Debian (на Ubuntu - те саме, лише шлях репозиторію linux/ubuntu). Усе роблю від root.

WordPress · Docker Compose linuxway.com.ua

Далі ті самі кроки з запису, тільки вже можна копіювати.

Крок 1. Каталог і секрети
#

Створюємо каталог проєкту й кладемо паролі бази в .env - окремо від compose.yml, щоб не світити їх у головному файлі:

1
mkdir wp-docker && cd wp-docker
1
2
3
# .env
DB_PASSWORD=ВАШ_СКЛАДНИЙ_ПАРОЛЬ
DB_ROOT_PASSWORD=ЩЕ_ОДИН_СКЛАДНИЙ_ПАРОЛЬ
.env docker compose підхоплює сам і підставляє в ${DB_PASSWORD}. Додай його в .gitignore - паролям не місце в репозиторії.

Крок 2. compose.yml
#

Увесь стек - в одному файлі. Розберемо його нижче, а поки - цілком:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
x-wp-env: &wp-env
  WORDPRESS_DB_HOST: db
  WORDPRESS_DB_USER: wpuser
  WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
  WORDPRESS_DB_NAME: wordpress
  WORDPRESS_CONFIG_EXTRA: |
    define( 'WP_REDIS_HOST', 'redis' );
    define( 'WP_CACHE', true );

services:
  db:
    image: mariadb:11
    restart: unless-stopped
    environment:
      MARIADB_DATABASE: wordpress
      MARIADB_USER: wpuser
      MARIADB_PASSWORD: ${DB_PASSWORD}
      MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 10

  redis:
    image: redis:7-alpine
    restart: unless-stopped

  wordpress:
    image: wordpress:php8.4-apache
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8080:80"
    environment: *wp-env
    volumes:
      - wp_data:/var/www/html

  wpcli:
    image: wordpress:cli-php8.4
    profiles: ["cli"]
    user: "33:33"
    environment:
      <<: *wp-env
      HOME: /tmp
    volumes:
      - wp_data:/var/www/html

volumes:
  db_data:
  wp_data:

Що тут важливо, по порядку:

  • db з healthcheck, а wordpress чекає на condition: service_healthy. Без цього WordPress стартує швидше за базу і падає з «Error establishing a database connection». Healthcheck - це те, що в ручному варіанті робив порядок команд, а тут робить сам compose.
  • Іменовані volume db_data і wp_data - дані переживають down/up і перестворення контейнерів. Без них перший же down з’їв би і базу, і сайт.
  • Redis object cache вмикається не змінними контейнера, а константами в wp-config.php - їх дає WORDPRESS_CONFIG_EXTRA.
  • Якорь x-wp-env (&wp-env / *wp-env) - щоб ті самі налаштування бачив і wordpress, і wpcli. Інакше wp-cli не знав би про WP_REDIS_HOST і стукав би в 127.0.0.1 замість сервісу redis.
  • wpcli - окремий сервіс у профілі cli: з docker compose up він не стартує (нема сенсу тримати його живим), його запускають разово через docker compose run --rm wpcli .... user: "33:33" - щоб писати у volume під тим самим www-data, що й офіційний образ (в образі wordpress:cli свій uid, і без цього плагіни не встановляться через права). HOME: /tmp - щоб wp-cli було куди класти кеш.

Крок 3. Піднімаємо
#

1
2
docker compose up -d
docker compose ps

up -d підтягне образи (якщо їх ще нема), створить мережу, volume і три контейнери. Завдяки healthcheck compose дочекається, поки база стане healthy, і лише тоді підніме WordPress. У ps маєш побачити три сервіси - db (healthy), redis, wordpress з проброшеним портом 8080.

Крок 4. Встановлюємо WordPress через wp-cli
#

Образ піднявся, але сайт ще не встановлений - це зробимо one-off запуском wpcli. Звернень до контейнера руками нема, усе через docker compose run:

1
2
3
4
docker compose run --rm wpcli wp core install \
  --url=http://localhost:8080 --title="Мій блог" \
  --admin_user=admin --admin_password='ПАРОЛЬ_АДМІНА' \
  --admin_email=admin@example.com

Крок 5. Вмикаємо Redis object cache
#

Ставимо плагін redis-cache, активуємо його і вмикаємо dropin - знову через wpcli:

1
2
docker compose run --rm wpcli wp plugin install redis-cache --activate
docker compose run --rm wpcli wp redis enable

WP_REDIS_HOST ми вже віддали через compose.yml (сервіс redis), тож плагін одразу знає, куди під’єднуватись.

Перевірка
#

1
docker compose run --rm wpcli wp redis status
1
2
3
Status: Connected
Client: Predis (v2.4.1)
Drop-in: Valid

Connected + Drop-in: Valid - кеш працює. Зверни увагу: Client: Predis, а не PhpRedis, як у ручному варіанті. Офіційний образ wordpress:cli не має розширення phpredis, тому плагін бере чистий PHP-клієнт Predis - у бандлі. Для кешу це не критично, усе працює; просто корисно знати, чому цифри різняться. А сам сайт уже віддає 200:

1
curl -sI http://localhost:8080
1
2
3
HTTP/1.1 200 OK
Server: Apache/2.4.68 (Debian)
X-Powered-By: PHP/8.4.26

Apache чи все-таки щось легше?
#

Маленька чесність наостанок: офіційний образ wordpress:*-apache віддає PHP як модуль Apache (mod_php), а не через PHP-FPM, як ми робили руками. Для одноразового стенду чи невеликого сайту це цілком нормально - образ готовий, працює з коробки. Але якщо хочеться саме FPM (а ще легше - nginx спереду) - це вже окрема розмова про вебсервер. База, Redis і сам WordPress при цьому не змінюються - міняється лише фронт.

Той самий стек, що й руками - Apache, PHP, MariaDB, Redis - тільки описаний одним compose.yml і піднятий однією командою. Руками ти розумієш, що всередині; у compose - керуєш цим як одним цілим. Одне доповнює інше.

WordPress по-дорослому - частина серії статей.
Частина 2: ця стаття (ти тут)

Related