Migrasi ke Docker

Ilustrasi perjalanan dari web panel ke Docker container
Dari Webuzo, CWP, aaPanel, sampai akhirnya Docker.

Hampir sepuluh tahun terakhir semua website yang saya kelola selalu berjalan di atas web panel. Dimulai dari Webuzo, lalu pindah ke CentOS Web Panel, sempat singgah di aaPanel, dan akhirnya sekarang semuanya saya pindahkan ke Docker. Tulisan ini merangkum alasan dan cara migrasinya.

Ilustrasi perjalanan dari web panel ke Docker container

Manajemen pakai panel

Panel sangat membantu di awal. Membuat domain, database, email, dan sertifikat SSL cukup dengan beberapa klik. Untuk satu atau dua website, cara ini masih masuk akal.

Masalah mulai terasa ketika jumlah website bertambah dan kebutuhannya berbeda-beda. Ada aplikasi lama yang hanya jalan di PHP 7.4, ada WordPress yang butuh PHP 8.3, ada OJS dengan kebutuhan ekstensi sendiri. Semuanya berbagi satu web server, satu MySQL, dan satu sistem operasi. Satu situs yang terinfeksi malware berpotensi menular ke situs lain di server yang sama, seperti yang pernah saya ceritakan di mitigasi malware di web server.

Webuzo

Webuzo adalah panel pertama yang saya pakai serius. Ringan dan mudah, tetapi versi gratisnya hanya menyediakan satu user untuk mengelola semuanya. SSL juga masih harus dipasang manual setiap tiga bulan.

CentOS Web Panel

CWP menyelesaikan masalah di Webuzo: multiuser, ModSecurity, dan auto SSL dari Let’s Encrypt. Bertahun-tahun CWP menjadi andalan. Sayangnya CWP terikat dengan keluarga CentOS. Ketika CentOS 8 dihentikan lebih awal dan CentOS 7 berakhir masa dukungannya pada Juni 2024, saya harus mencari jalan keluar.

aaPanel

aaPanel sempat menjadi pengganti karena bisa berjalan di Ubuntu dan Debian. Tampilannya rapi dan instalasinya cepat. Tetapi pada dasarnya polanya sama: semua aplikasi tetap menumpuk di satu sistem. Setiap kali upgrade PHP atau MySQL, saya harus berdoa supaya tidak ada situs yang rusak.

Di titik ini saya sadar yang saya butuhkan bukan panel yang lebih baik, melainkan cara kerja yang berbeda.

Docker

Dengan Docker, setiap aplikasi berjalan di container sendiri lengkap dengan versi PHP, web server, dan databasenya. Satu situs bermasalah tidak menyeret situs lain. Konfigurasi juga tersimpan sebagai file teks yang bisa disimpan di Git, jadi membangun ulang server tidak lagi bergantung pada ingatan.

Diagram arsitektur reverse proxy dengan container per situs

Polanya seperti diagram di atas. Satu reverse proxy berdiri di depan dan menerima semua trafik HTTPS, lalu meneruskannya ke container masing-masing situs. Database hanya bisa diakses dari network internal situsnya, tidak pernah dibuka ke internet.

1. Struktur direktori

Saya memakai satu direktori per situs di /opt/stack:

/opt/stack/
├── proxy/          # Caddy
├── situs-a/        # WordPress
│   ├── compose.yaml
│   ├── .env
│   ├── app/
│   └── db/
└── ojs/

2. Reverse proxy

Buat network bersama untuk proxy, lalu jalankan Caddy. Caddy otomatis mengurus sertifikat Let’s Encrypt, fitur yang dulu menjadi alasan saya memilih CWP.

docker network create proxy

Isi proxy/Caddyfile cukup sesederhana ini:

situs-a.ac.id {
    reverse_proxy situs-a-web-1:80
}

jurnal.ac.id {
    reverse_proxy ojs-app-1:80
}

3. Compose untuk setiap situs

Contoh situs-a/compose.yaml untuk WordPress:

services:
  web:
    image: nginx:1.27-alpine
    volumes:
      - ./app:/var/www/html:ro
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    networks: [internal, proxy]
    restart: unless-stopped

  php:
    image: wordpress:php8.3-fpm
    volumes:
      - ./app:/var/www/html
    env_file: .env
    networks: [internal]
    restart: unless-stopped

  db:
    image: mariadb:11.4
    volumes:
      - ./db:/var/lib/mysql
    env_file: .env
    networks: [internal]
    restart: unless-stopped

networks:
  internal:
  proxy:
    external: true

Perhatikan hanya container web yang tergabung ke network proxy. Container php dan db tidak bisa dijangkau dari luar.

Langkah migrasi dari panel

Proses migrasi setiap situs kurang lebih sama:

1. Turunkan TTL DNS beberapa hari sebelumnya, misalnya menjadi 300 detik, supaya perpindahan cepat terasa.

2. Dump database dan salin file dari server lama.

mysqldump --single-transaction -u user -p nama_db > situs-a.sql
rsync -avz user@server-lama:/home/user/public_html/ /opt/stack/situs-a/app/

3. Jalankan container, lalu import database.

cd /opt/stack/situs-a
docker compose up -d
docker compose exec -T db mariadb -u root -p"$DB_ROOT_PASSWORD" nama_db < situs-a.sql

4. Uji dengan mengarahkan domain ke IP server baru lewat file hosts di laptop sendiri. Jika semua normal, baru ubah record DNS.

5. Hapus file dump setelah selesai.

Langkah terakhir ini sering terlupa. Saya pernah menulis kenapa file .sql dan .zip sisa migrasi wajib dihapus.

Update jadi lebih tenang

Upgrade versi PHP sekarang cukup mengganti tag image di compose.yaml. Kalau ternyata bermasalah, kembalikan tag lama dan jalankan ulang. Tidak ada lagi drama upgrade satu server penuh.

Output terminal docker compose ps dan docker compose up

docker compose pull
docker compose up -d

Yang perlu diperhatikan

Docker bukan tanpa kekurangan. Tidak ada lagi tombol klik-klik seperti di panel, jadi perlu terbiasa dengan terminal. Jika butuh tampilan visual, Portainer bisa membantu. Image lama juga menumpuk dan memakan disk, sehingga perlu sesekali dibersihkan dengan docker image prune.

Email adalah satu-satunya layanan yang tidak saya pindahkan ke Docker. Mengelola mail server sendiri terlalu merepotkan, jadi saya serahkan ke layanan pihak ketiga dan cukup mengatur record MX-nya.

Terakhir, container tidak menggantikan backup. Volume database tetap harus dicadangkan ke luar server, misalnya dengan immutable backup ke object storage.

Setelah semua situs pindah, saya justru merasa lebih dekat dengan server. Semua yang berjalan tertulis jelas di file konfigurasi, bukan tersembunyi di balik panel.

Comments

No comments yet. Why don’t you start the discussion?

Tinggalkan Balasan