Iată a treia postare, și ultima, din Saga Migrării de WordPress, o serie care prezintă migrarea unui website WordPress deja existent pe un alt host, în Docker.
Pentru a te familiariza puțin cu mediul de lucru în Docker și Docker Compose, citește prima dată partea a doua, Acomodarea cu Docker.
Configurarea structurii directorului website-ului
Pentru a păstra datele în noul container Docker, va trebui să stocăm datele într-un volum director pe care îl vom monta pe container-ul nostru Docker.
Prima dată, dacă nu avem deja fișierul zip, să comprimăm site-ul nostru WordPress într-un fișier de tip zip numitsite.zip
, pe calculatorul local. Se poate folosi utilitarul zip în interiorul directorului, pentru a înlătura directorul părinte din fișierul zip final.
cd local/site1.com; zip -r ../site.zip *
În continuare, pe Linode vom crea un director pentru site-ul nostru, și vom copia datele de pe calculatorul nostru pe host-ul Linode. Ia aminte că 192.0.2.0 este un IP de test, schimbă-l cu IP-ul server-ului tău.
# on the Linode instance, create the folder and its parents, if they don't exist
mkdir -pv /var/www/site1.com/src
mkdir -pv /var/www/site1.com/database/data
mkdir -pv /var/www/site1.com/database/initdb.d
# from the local computer, copy the zip file and database.sql to the Linode instance
scp local/site1.com/database.sql your_username@192.0.2.0:/var/www/site1.com/database/initdb.d
scp local/site1.com/site.zip your_username@192.0.2.0:/var/www/site1.com
# on the Linode instance, decompress the file
cd /var/www/site1.com/
apt-install unzip
unzip site.zip -d src/
rm site.zip
Directorul nostru ar trebui să aibă următoarea structură:
.
└── site1.com
├── .env
├── database
│ ├── data
│ └── initdb.d
│ └── database.sql
├── docker-compose.yml
└── src
├── …
├── wp-admin
├── …
└── xmlrpc.php
Acum că am decis care va fi structura directorului nostru, creăm un fișier atașat .env
care va păstra datele de identitate. Poți folosi vim pentru a crea fișierele, sau editorul tău favorit.
De obicei scriu fișierele în VSCode, apăs Ctrl+C
, apoi merg în linia de comandă, vim
cu numele fișierului, gg+dG
să șterg tot conținutul, i
să trec pe modul de inserare, Shift+Ctrl+V
să lipesc conținutul din VSCode, ESC
și :wq!
să ies din fișier și să se scrie schimbările. O altă opțiune ar fi să setez acces remote la server din VSCode.
DB_ROOT_PASSWORD=my_secret_passwd
DB_NAME=my_secret_name
DB_USER=my_secret_user
DB_PASSWORD=my_secret_passwd2
Optional, pentru că fișierul .env conține informații sensibile, poți să-l incluzi în fișierele .gitignore
și .dockerignore
ale proiectului, fapt care le va spune lui Git and Docker ce fișiere să nu copieze în depozitele Git și respectiv în imaginile Docker (dacă vom dori versionare).
.env
.git
docker-compose.yml
.dockerignore
Acum, să creăm fișierul docker-compose.yml.
version: '3.7'
networks:
wp-back-myblog:
services:
mysql_myblog:
container_name: wp_myblog_db
image: mysql:5.7
volumes:
- ./database/data:/var/lib/mysql
- ./database/initdb.d:/docker-entrypoint-initdb.d
restart: always
env_file: .env
environment:
MYSQL_ROOT_PASSWORD: $DB_ROOT_PASSWORD
MYSQL_DATABASE: $DB_NAME
MYSQL_USER: $DB_USER
MYSQL_PASSWORD: $DB_PASSWORD
networks:
- wp-back-myblog
command:
--default-authentication-plugin=mysql_native_password
wp_myblog:
container_name: wp_myblog
depends_on:
- mysql_myblog
image: WordPress
volumes:
- ./src:/var/www/html
ports:
- 1234:80
networks:
- wp-back-myblog
restart: always
env_file: .env
environment:
WordPress_DB_HOST: mysql_myblog:3306
WordPress_DB_NAME: $DB_NAME
WordPress_DB_USER: $DB_USER
WordPress_DB_PASSWORD: $DB_PASSWORD
Aici definim:
versiunea de fișier
pentru Compose- două
servicii
, unul pentru baza de date, altul pentru aplicația WordPress image
îi spune lui Compose ce imagine să aducă să creeze containerulcontainer_name
specifică un nume pentru containerrestart
definește politica de restart a container-uluienv_file
îi spune lui Compose că am dori să adăugăm variabile de environment dintrun fișier numit.env
, situat în contextul nostru de buildenvironment
ne permite să adăugăm variabile de environment adiționale, pe lângă cele definite în fișierul nostru.env
volumes
montează bind mounts:- directorul local
./database/data
, montat pe directorul/var/lib/mysql
pe container, este directorul standard de date pentru MySQL pe majoritatea distribuțiilor - directorul local
./database/initdb.d
, montat pe directorul/docker-entrypoint-initdb.d
pe container, va fi folosit pentru prepopularea bazei de date - montat pe directorul
./src
, montat pe directorul/var/www/html
pe container, va fi casa website-ului nostru
- directorul local
networks
specifică rețeaua care va fi împărțită de aplicațiile noastredepends_on
se asigură că containerele noastre vor porni în ordinea dependențelor, cu containerulwp_myblog
pornind după containerulmysql_myblog
ports
este o opțiune care expune port-ul1234
, vrem ca WordPress să fie accessibil prin intermediul port-ului 1234 pe host-ul nostrucommand
MySQL 8.0 a schimbat plugin-ul implicit de autentificare, și clienții mai vechi s-ar putea să nu se poată conecta, trebuie adăugat--default-authentication-plugin=mysql_native_password
(src)
Când containerul mysql_myblog
este pornit pentru prima dată, o nouă bază de date cu numele specificat va fi creată și inițializată cu variabilele oferite în configurație. Mai mult, va executa fișierele cu extensii.sh
, .sql
și .sql.gz
care se găsesc în /docker-entrypoint-initdb.d
. Vom popula serviciul nostru mysql
prin montarea exportului SQL în acest director, iar fișierele SQL vor fi importate în mod implicit în baza de date specificată de variabila MYSQL_DATABASE
. (src)
În timp ce bind mounts
sunt dependente de structura directorului pe mașina de host, volumes
sunt administrate în întregime de către Docker. (src)
Acum, crează containerele cu docker-compose up
și indicatorul -d
, care va rula containerele mysql_myblog
și wp_myblog
pe fundal, și verifică starea serviciilor.
# check status
docker-compose ps
# see logs
docker-compose logs
# follow specific log for testing
docker logs -f a80
Dacă starea serviciilor este up
, ar trebui să poți accesa 192.0.2.0:1234 și să vezi website-ul tău WordPress. În continuare, vom folosi NGINX să corelăm https://site1.com cu aplicația noastră situată la 192.0.2.0:1234.
Folosirea NGINX ca Reverse Proxy pentru containerele noastre Docker
Vrem ca website-ul nostru să fie securizat, așa că vom activa HTTPS
atât în fișierul wp-config.php file cât și în fișierul de configurare pentru nginx, ca să evităm probleme de genul ‘The page isn’t redirecting properly‘. Să adăugăm următoarele constante în wp-config.php
$_SERVER['HTTPS'] = 'on';
define('FORCE_SSL_ADMIN', true);
define('FORCE_SSL_LOGIN', true);
define('FORCE_SSL_CONTENT', true);
Înainte de a obține efectiv un certificat Let’s Encrypt trebuie instalat Certbot. Certbot este clientul oficial pentru Let’s Encrypt și totodată cea mai ușoară cale de a obține un certificat. Se poate rula certbot cu opțiunea --staging
pentru a-ți testa setările, apoi se poate schimba această opțiune cu --force-renewal
pentru a obține certificatele finale. Sunt stabilite limitări de frecvență care asigură că oamenii nu abuzează de serviciu, ai grijă să folosești mediul de staging cât timp testezi.
# stop nginx, certbot conflicts with nginx on port 80
sudo service nginx stop
# install certbot
sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot
# create the certificate
certbot certonly --standalone --preferred-challenges http --email admin@site1.com --noninteractive --quiet --agree-tos -d site1.com -d www.site1.com --expand
# list the certificates
sudo certbot certificates
# test the renewal script
sudo certbot renew --dry run
# start nginx
sudo service nginx start
Crează un fișier de configurare pentru nginx numit site1.com.conf
în /etc/nginx/conf.d
. Acest fișier îi va permite lui nginx să facă redirecționările potrivite de la HTTP la HTTPS, și proxy către aplicația WordPress.
server {
listen 80;
listen [::]:80;
server_name site1.com www.site1.com;
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name site1.com www.site1.com;
root /var/www/site1.com;
index index.php;
ssl_certificate /etc/letsencrypt/live/site1.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/site1.com/privkey.pem;
gzip on;
gzip_comp_level 3;
gzip_types text/css image/jpg image/jpeg image/png image/svg;
location / {
proxy_pass http://0.0.0.0:1234;
proxy_set_header Accept-Encoding "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
În fișierul de mai sus, avem următoarele opțiuni:
listen
îi spune lui NGINX să asculte port-ul80
, respectiv443
server_name
definește numele server-ului nostru și blocul de server care ar trebui folosit pentru cereri către serverul nostrurewrite
este folosit pentru redirecționarea traficului total de la HTTP la HTTPSindex
definește fișierele care vor fi folosite ca indexe în timpul procesării cererilor către serverul tăuroot
numește directorul rădăcină pentru cererile către server-ul nostrulocation /
este blocul în care directive specifice vor face proxy la cererile către aplicația WordPress
Și… Voilà! Dacă rulăm nginx reload
ar trebui să putem accesa website-ul nostru la https://site1.com 🤗
Pentru debugging, putem folosi netstat -nlp
să verificăm port-urile care ascultă, docker ps -a
și docker logs -f wp_myblog
pentru a urmări logurile, nginx -t
pentru erorile din nginx. Pentru a face copii de rezervă putem folosi mysqldump
și ceva serviciu de cron cu scp
pentru blog (sau versionare).
# test connection to the database
docker exec -it wp_myblog_db mysql -u$DB_USER --password=$DB_PASSWORD $DB_NAME
# backup
docker exec wp_blogmap_db /usr/bin/mysqldump -u root --password=$DB_PASSWORD $DB_NAME > backup.sql
# restore
cat backup.sql | docker exec -i wp_blogmap_db /usr/bin/mysql -u$DB_USER --password=$DB_PASSWORD $DB_NAME
Pentru a migra website-uri WordPress multiple pe același host, este nevoie doar să adaugi structura directorului pentru fiecare dintre ele, să adaugi fișiere de configurare nginx pentru fiecare, și să schimbi port-ul din 1234 în alte port-uri libere.
Mai sunt multe alte aspecte de care nu mă voi atinge în postarea aceasta, cum ar fi creșterea securității, rularea containerelor ca și user-ul curent, folosirea lui nginx proxy și certbot ca imagini Docker, rularea unui serviciu crontab pentru actualizarea certificatelor de la certbot, CI/CD.. Cum să scapi de WordPress și să faci o aplicație Node.js. Cum să te asiguri că ai montat volumele corect și nu-ți pierzi datele.. Ansible cine? 😅
De asemenea, sunt multe lucruri pe care le descoper despre Docker chiar acum, ăsta-i doar vârful iceberg-ului. Nu ezitați să mă contactați dacă vedeți informații eronate, sau parolele mele de la server afișate liber. 😅 Sper doar că această postare a fost de ajutor pentru cei care sunt la început cu Docker și vor să învețe mai multe despre el. 🌱🌱🌞
Mă bucur și că am aflat de Le blog de Laurel, face niște ilustrații extraordinare. Bine.. fiecare zi e o Sărbătoare 😍
Extra Junk
Examplu de structură de directoare pentru mai multe bloguri și nginx instalat pe host:
.
├── site1.com
│ ├── .env
│ ├── database
│ │ ├── data
│ │ └── initdb.d
│ │ └── database.sql
│ ├── docker-compose.yml
│ └── src
│ ├── …
│ ├── wp-admin
│ ├── …
│ └── xmlrpc.php
└── site2.com
├── .env
├── database
│ ├── data
│ └── initdb.d
│ └── database.sql
├── docker-compose.yml
└── src
├── …
├── wp-admin
├── …
└── xmlrpc.php
Examplu de structură de directoare pentru folosirea imaginii jwilder/nginx-proxy (după asta )
.
├── site1.com
│ ├── .dockerignore
│ ├── .env
│ ├── .gitignore
│ ├── database
│ ├── docker-compose.yml
│ └── src
├── site2.com
│ ├── .dockerignore
│ ├── .env
│ ├── .gitignore
│ ├── database
│ ├── docker-compose.yml
│ └── src
└── nginx
└── docker-compose.yml
version: '3'
services:
nginx:
image: jwilder/nginx-proxy:alpine
container_name: nginx
restart: always
labels:
com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: 'true'
ports:
- 80:80
- 443:443
volumes:
- /srv/nginx/data/certs:/etc/nginx/certs:ro
- /srv/nginx/data/conf.d:/etc/nginx/conf.d
- /srv/nginx/data/vhost.d:/etc/nginx/vhost.d
- /srv/nginx/data/html:/usr/share/nginx/html
- /var/run/docker.sock:/tmp/docker.sock:ro
networks:
- proxy
letsencrypt:
image: jrcs/letsencrypt-nginx-proxy-companion
container_name: letsencrypt
volumes:
- /srv/nginx/data/vhost.d:/etc/nginx/vhost.d
- /srv/nginx/data/certs:/etc/nginx/certs:rw
- /srv/nginx/data/html:/usr/share/nginx/html
- /var/run/docker.sock:/var/run/docker.sock:ro
depends_on:
- nginx
networks:
- proxy
networks:
proxy:
driver: bridge
jwilder/nginx-proxy
DB_CONTAINER=my_container
DB_ROOT_PASSWORD=my_passwd
DB_NAME=my_user
DB_PASSWORD=my_passwd2
WP_CONTAINER=my_container2
VIRTUAL_HOST=site1.com,www.site1.com
LETSENCRYPT_EMAIL=admin@site1.com
version: '3'
services:
db:
container_name: $DB_CONTAINER
image: mysql:5.7
restart: always
env_file: .env
volumes:
- ./database/data:/var/lib/mysql
- ./database/initdb.d:/docker-entrypoint-initdb.d
environment:
MYSQL_RANDOM_ROOT_PASSWORD: $DB_ROOT_PASSWORD
MYSQL_DATABASE: $DB_NAME
MYSQL_USER: $DB_USER
MYSQL_PASSWORD: $DB_PASSWORD
command:
--default-authentication-plugin=mysql_native_password
wp:
container_name: $WP_CONTAINER
depends_on:
- db
image: WordPress
restart: always
ports:
- "1234:80"
volumes:
- ./src:/var/www/html
env_file: .env
environment:
WordPress_DB_HOST: ${DB_CONTAINER}:3306
WordPress_DB_NAME: $DB_NAME
WordPress_DB_USER: $DB_USER
WordPress_DB_PASSWORD: $DB_PASSWORD
VIRTUAL_HOST: $VIRTUAL_HOST
LETSENCRYPT_HOST: $VIRTUAL_HOST
LETSENCRYPT_EMAIL: $LETSENCRYPT_EMAIL
LETSENCRYPT_TEST: 'true'
networks:
default:
external:
name: nginx_proxy
Examplu de structură de directoare pentru un singur website si nginx-proxy si certbot drept imagini Docker (după asta)
└── site1.com
├── .dockerignore
├── .env
├── .gitignore
├── database
│ ├── data
│ └── initdb.d
├── docker-compose.yml
├── nginx-conf
│ ├── nginx.conf
│ └── options-ssl-nginx.conf
└── src
├── …
├── wp-admin
└── xmlrpc.php
version: '3'
services:
db:
image: mysql:8.0
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MYSQL_ROOT_PASSWORD=$DB_ROOT_PASSWORD
- MYSQL_DATABASE=$DB_NAME
- MYSQL_USER=$DB_USER
- MYSQL_PASSWORD=$DB_PASSWORD
volumes:
- ./database/data:/var/lib/mysql
- ./database/initdb.d:/docker-entrypoint-initdb.d
command: '--default-authentication-plugin=mysql_native_password'
networks:
- app-network
WordPress:
depends_on:
- db
image: WordPress:5.1.1-fpm-alpine
container_name: WordPress
restart: unless-stopped
env_file: .env
environment:
- WordPress_DB_HOST=db:3306
- WordPress_DB_USER=$DB_USER
- WordPress_DB_PASSWORD=$DB_PASSWORD
- WordPress_DB_NAME=$DB_NAME
volumes:
- ./src:/var/www/html
networks:
- app-network
webserver:
depends_on:
- WordPress
image: nginx:1.15.12-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./src:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- ./src:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email admin@site1.com --agree-tos --no-eff-email --force-renewal -d site1.com -d www.site1.com
volumes:
certbot-etc:
networks:
app-network:
driver: bridge
Referințe
- Docker Engine overview | Docker Documentation
- Environment variables in Compose | Docker Documentation
- Get Docker Engine – Community for Ubuntu | Docker Documentation
- GitHub – jwilder/nginx-proxy: Automated nginx proxy for Docker containers using docker-gen
- GitHub – selloween/docker-multi-WordPress: Run multiple WordPress Docker containers with NGINX Proxy, LetsEncrypt and PHP Composer
- Host multiple websites on one VPS with Docker and Nginx
- Hosting WordPress over HTTPS with Docker – DEV Community 👩💻👨💻
- How To Install WordPress With Docker Compose | DigitalOcean
- How to restore a MySQL database using Docker
- Learn DevOps basics with this free 2-hour Docker course
- Local WordPress Development with Docker
- Move existing WordPress site into Docker – Dots and Brackets: Code Blog
- Moving a WordPress site into a Docker Container | Stephen AfamO’s Blog
- Multiple WordPress Sites on Docker | Autoize
- MySQL :: MySQL Installation Guide :: 7.3.1 Basic Steps for MySQL Server Deployment with Docker
- Play with Docker
- Putting Multiple WordPress Containers into Production – Proxy Container – PattonWebz
- Vagrant vs. Docker: Which Is Better for Software Development Environments? – DZone DevOps