Upgrade WordPress Docker: Fix DNS, PHP, dan MySQL 8.4

Tiga Isu, Satu Upgrade

Baru-baru ni aku kena deal dengan tiga isu sekaligus bila upgrade WordPress yang jalan dalam Docker. DNS tak boleh resolve, PHP masih 7.4, dan MySQL auto-upgrade dari 8.0 ke 8.4 yang terus broke database connection.

Aku document semua fix kat sini. Kalau ko hadapi isu sama, harap ni membantu.

Masalah 1: DNS Container Tak Boleh Resolve

Tengok dalam wp-content/debug.log, ada warning macam ni:

translations_api(): WordPress could not establish a secure connection to WordPress.org

Masalah ni biasanya sebab Docker container guna DNS yang salah atau tak configured langsung.

Fix: Set DNS Global untuk Docker

Edit /etc/docker/daemon.json:

{
  "dns": ["192.168.1.2", "192.168.1.1"]
}

Tukar IP tu ikut DNS server ko sendiri. Lepas tu restart Docker dan recreate container:

systemctl daemon-reexec
systemctl restart docker

docker-compose down
docker-compose up -d

Masalah 2: PHP Masih Versi 7.4

WordPress tunjuk warning ni:

Your site is running on an outdated version of PHP (7.4.29)...

Sebabnya image dalam docker-compose.yml tak dikunci ke versi PHP terbaru.

Fix: Tukar Image ke PHP 8.3

Dalam docker-compose.yml, tukar baris image:

image: wordpress:php8.3-fpm

Lepas tu pull dan restart:

docker-compose pull
docker-compose up -d

Masalah 3: MySQL Auto-Upgrade Broke Database Connection

Ini yang paling sakit. MySQL Docker auto-upgrade dari 8.0.30 ke 8.4.5, terus WordPress bagi error:

Error establishing a database connection

Log MySQL pula tunjuk dua error ni:

unknown variable 'default-authentication-plugin=mysql_native_password'
Plugin 'mysql_native_password' is not loaded

MySQL 8.4 dah buang sokongan untuk mysql_native_password. Plugin tu deprecated sejak 8.0, dan 8.4 terus remove. Default sekarang ialah caching_sha2_password.

Langkah 1: Buang Config Lama

Dalam docker-compose.yml, buang atau comment out baris ni:

# REMOVE this block:
# command:
#   - '--default-authentication-plugin=mysql_native_password'

Langkah 2: Reset Plugin dan Password via Safe Mode

Masuk ke dalam container MySQL, jalankan dalam safe mode:

mysqld --skip-grant-tables --skip-networking --user=mysql &

Lepas tu dalam MySQL CLI, update plugin untuk kedua-dua user:

UPDATE mysql.user 
  SET plugin = 'caching_sha2_password', authentication_string = '' 
  WHERE user IN ('root', 'wordpress');

FLUSH PRIVILEGES;

Langkah 3: Set Semula Password

Restart container, masuk semula sebagai user wordpress:

docker exec -it azmidotmy-wp-database mysql -u wordpress

Set password baru dengan betul:

ALTER USER 'root'@'localhost' IDENTIFIED BY 'rootpassword123!';
ALTER USER 'wordpress'@'%' IDENTIFIED BY 'password123!';

Bonus: Kunci Versi Supaya Tak Auto-Upgrade Lagi

Kalau ko biarkan image guna tag latest atau tag minor, ada risiko auto-upgrade berlaku secara senyap. Kunci versi explicit dalam docker-compose.yml:

image: mysql:8.4.5

Buat benda sama untuk WordPress dan PHP. Upgrade manual bila dah ready, bukan bila Docker rasa nak upgrade sendiri.

Ringkasan Fix

  • DNS: Tambah dns dalam /etc/docker/daemon.json, restart Docker.
  • PHP: Tukar image ke wordpress:php8.3-fpm, pull semula.
  • MySQL 8.4: Buang default-authentication-plugin, migrate ke caching_sha2_password, set semula password.
  • Versi: Kunci image tag explicitly. Jangan trust latest.

Tips Tambahan: Manage Semua Ni dengan Ansible

Kalau ko manage lebih dari satu server WordPress, buat semua benda ni manually setiap kali adalah a waste of time. Ansible boleh automate banyak bahagian ni.

Tip 1: Deploy daemon.json Guna Ansible Template

Jangan hardcode DNS server berbeza-beza kat setiap host manually. Guna template:

# roles/docker/templates/daemon.json.j2
{
  "dns": {{ docker_dns_servers | to_json }}
}
# playbook
- name: Configure Docker DNS
  template:
    src: daemon.json.j2
    dest: /etc/docker/daemon.json
  notify:
    - restart docker

# group_vars/all.yml
docker_dns_servers:
  - "192.168.1.2"
  - "192.168.1.1"

Senang nak tukar DNS untuk semua host sekaligus. Ubah kat group_vars, run playbook, siap.

Tip 2: Kunci Versi Image dalam Ansible Vars

Daripada edit docker-compose.yml secara manual setiap kali ada upgrade, simpan versi dalam Ansible variables:

# group_vars/wordpress.yml
wp_image: "wordpress:php8.3-fpm"
mysql_image: "mysql:8.4.5"
# roles/wordpress/templates/docker-compose.yml.j2
services:
  wordpress:
    image: {{ wp_image }}
  database:
    image: {{ mysql_image }}

Bila nak upgrade, tukar versi kat satu tempat je. Ansible propagate ke semua server yang affected.

Tip 3: Automate MySQL Password Reset dengan Ansible

Proses reset plugin dan password tadi boleh jadi messy kalau buat manually. Ansible ada module community.mysql.mysql_user yang boleh handle ni dengan bersih:

- name: Ensure MySQL user pakai caching_sha2_password
  community.mysql.mysql_user:
    login_host: 127.0.0.1
    login_port: 3306
    login_user: root
    login_password: "{{ mysql_root_password }}"
    name: wordpress
    host: "%"
    password: "{{ mysql_wp_password }}"
    plugin: caching_sha2_password
    state: present
    update_password: always

Simpan password dalam Ansible Vault, bukan plaintext. Kalau ko belum guna Vault lagi, ini masa yang sesuai nak start.

Leave a Comment