Cấu hình tự động deploy ứng dụng Laravel với Deployer trên CentOS
ToC
Giới thiệu
Laravel là một open-source PHP web framework được thiết kế để thực hiện các nhiệm vụ cơ bản của việc phát triển web như authentication, routing, caching một cách dễ dàng.
Deployer là một open-source PHP deployment tool hỗ trợ các framework phổ biến như: Laravel, CodeIgniter, Symfony, và Zend Framework.
Deployer thực hiện việc tự đông deploy bằng cách clone
source code từ git repo trên server, cài đặt các dependencies
với Composer sau đó cấu hình ứng dụng với kịch bản định sẵn. Điều này giúp bạn tập trung vào việc phát triển, thay vì tốn thời gian cho việc upload và cấu hình server.
Điểm mạnh khác của Deployer là nó hỗ trợ chúng ta Zero downtime deployments bằng cơ chế SymLink
trên Linux, đồng thời cho phép rollback về phiên bản trước đó khi cần thiết.
Ở hướng dẫn này, bạn có thể thực hiện một deploy cơ bản từ máy local lên một server CentOS 8 với thời gian Down time = 0.
Chuẩn bị môi trường
Máy local (môi trường phát triển)
- OS: Windows 10 Home Single Language 64-bit
- Development Tool:
- Editor: Visual Studio Code Version 1.40.2
Máy server (môi trường triển khai)
- OS: CentOS Linux 8 (Core)
- Development Tool:
- LEMP Stack (Linux + Nginx+ MySQL/MongoDB+ PHP)
- PHP 7.2.11 (cli)
- Nginx version: nginx/1.14.1
- MySql version: 8.0.17
- Git git version 2.18.1 (Linux)
- NodeJS v10.16.3 (Linux)
- LEMP Stack (Linux + Nginx+ MySQL/MongoDB+ PHP)
- Editor: Nano
Git server
- https://github.com/ Tạo sẵn một github repo để push code lên trong mỗi lần deploy.
Bắt đầu cài đặt
Bước 1 — Thiết lập môi trường Local Development
Đầu tiên, chúng ta sẽ thiết lập môi trường phát triển trên máy local để sẵn sàng cho Deployer hoạt động.
Deployer sẽ tự động điều khiển toàn bộ quá trình upload code và chạy các lệnh cài đặt theo kịch bản của chúng ta.
Note: Nếu bạn code trên môi trường Linux thì việc cài đặt Deployer sẽ hơi khác hướng dẫn dưới đây :D Cơ bản là dễ hơn nhiều nhé. Vào link này làm theo là xong https://deployer.org/docs/getting-started.html
1.1 Cài đặt Deployer
Trên máy local, mở gitbash
, tạo một thư mục mới để lưu file Deployer Excecute. Ở đây mình tạo folder trong ổ C:\ /c/Users/tuanm/deployer
Tải về deployer.phar
$ curl -LO https://deployer.org/deployer.phar
Kiểm tra lại file đã tải xem đúng với mã hash mới nhất trên trang chủ của Deployer chưa?
6.7.3 - a00dd2c9e09e8d809ae14ad695578181a177cea7
$ php -r "if (hash_file('sha1', 'deployer.phar') === 'a00dd2c9e09e8d809ae14ad695578181a177cea7') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('deployer.phar'); } echo PHP_EOL;"
Output như bên dưới là OK.
Installer verified
Đổi tên deployer.phar
thành dep
cho dễ nhớ.
$ mv deployer.phar dep
Cấp quyền thực thi cho file dep
:
$ chmod +x dep
Test thử cái coi: Ở nguyên folder đó, gõ: ./dep
Ra như hình dưới là sắp ngon rồi đấy.
Hiện tại command dep
chỉ chạy trong folder chứa nó. Muốn nó chạy ở mọi nơi thì cần thêm nó vào PATH
của windows
Thêm mới đường dẫn đến folder chứa file dep
đã tải về ở bước trước.
OK, xong các bước trên chúng ta có thể gõ lệnh dep
ở mọi nơi rồi.
$ dep
Deployer 6.7.3
Usage:
command [options] [arguments]
Options:
-h, --help Display this help message
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi Force ANSI output
--no-ansi Disable ANSI output
-n, --no-interaction Do not ask any interactive question
-f, --file[=FILE] Specify Deployer file
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Available commands:
autocomplete Install command line autocompletion capabilities
help Displays help for a command
init Initialize deployer in your project
list Lists commands
run Run any arbitrary command on hosts
self-update Updates deployer.phar to the latest version
ssh Connect to host through ssh
debug
debug:task Display the task-tree for a given task
1.2 Khởi tạo 1 project Laravel bằng Composer
$ composer create-project --prefer-dist laravel/laravel laravel-app
Tạo xong rồi chuyển sang bước 2, push code lên git repo của mình.
Bước 2 — Push Code lên Github
Đăng nhập vào Github và tạo mới 1 project để push code. Ví dụ: https://github.com/hapo-tuannd/laravel-base
Trên máy local, Mở gitbash
tại folder source code, ví dụ này là: D:\Dev\Laravel\laravel-app
. Run các command sau: (có thể yêu cầu đăng nhập)
git init
git add .
git commit -m "first commit"
git remote add origin https://github.com/hapo-tuannd/laravel-base.git
git push -u origin master
Done push source lên Github
$ git push -u origin master
Counting objects: 113, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (95/95), done.
Writing objects: 100% (113/113), 58.39 KiB | 3.65 MiB/s, done.
Total 113 (delta 11), reused 0 (delta 0)
remote: Resolving deltas: 100% (11/11), done.
To https://github.com/hapo-tuannd/laravel-base.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
OK, tiếp tục chuyển sang bước 3 trên máy server nhé.
Bước 3 — Cấu hình Deployer User
3.1 Khởi tạo deployer
user
Deployer
sử dung giao thức SSH để thực hiện các command trên server. Do đó, ở bước đầu tiên, chúng ta sẽ tạo ra một user
mới, cái mà Deployer có thể dùng để login vào và thực hiện các command qua SSH.
Server yêu cầu chạy Linux và đã cài LEMP Stack (Linux + Nginx + MySQL/MongoDB + PHP).
Bắt đầu tạo user mới có tên là deployer
và cấu hình nó:
$ sudo adduser deployer
Laravel
cần quyền đọc ghi dữ liệu để lưu cache file và upload file. Do đó, các thư mục tạo bởi deployer
phải có quyền đọc ghi qua Nginx web server
. Thêm nhóm quyền nginx
vào user deployer
bằng command sau:
$ sudo usermod -aG nginx deployer
Tiếp theo, cần cấu hình mặc định quyền khi tạo mới file, folder bằng user deployer
là 644 (file) và 755 (folder). Điều này giúp cho deployer
có thể đọc và ghi file, trong khi các nhóm hoặc user khác có thể đọc được.
Thực hiện cấu hình này bằng lệnh umask
=022 như sau:
$ sudo chfn -o umask=022 deployer
Source code upload lên server sẽ lưu ở /var/www/html/laravel-app
, nên chúng ta cần đổi ownership
của folder cho user deployer
và nhóm người dùng nginx
:
$ sudo chown deployer:nginx /var/www/html/laravel-app
User deployer
cần quyền sửa các file và folder trong /var/www/html/laravel-app
ngay cả khi được tạo sau này. Như vậy mọi file, folder, sub-folder được tạo trong folder đều kế thừa permission của folder cha. Thực hiện câu lệnh sau để set group id cho folder:
$ sudo chmod g+s /var/www/html/laravel-app
3.2 Kết nối server với Github
Deployer sẽ clone Git repo về máy server qua SSH, vì vậy ở bước này sẽ hướng dẫn các bạn generate SSH key
để cấu hình trên Github. Nếu ở bước 2 các bạn đã push code bằng cách SSH thì bước này cũng tương tự như vậy nhé.
Thao tác trên máy server: chuyển về user deployer
vừa tạo ở bước 3.1
$ su - deployer
Tiếp theo, generate SSH key
pair với deployer
user. Bước này bạn có thể cần accept tên file, password mặc định. (Enter 3 phát là được =))).
$ ssh-keygen -t rsa -b 4096
Hiển thị public key vừa tạo:
$ cat ~/.ssh/id_rsa.pub
Copy public key này và cấu hình SSH trên phần setting của Github. Tham khảo chi tiết ở đây nhé:
Test thử kết nối trên máy server với Github phát xem sao:
$ ssh -T git@github.com
Hi hapo-tuannd! You've successfully authenticated, but GitHub does not provide shell access.
OK, để cửa sổ đó, mình quay về máy local làm tiếp. (Mở 1 gitbash mới nhé).
3.3 Kết nối server với máy local
Ở máy local, chúng ta cũng sẽ kết nối đến máy server qua SSH. Bước này chúng ta sẽ generate SSH key
ở máy local, rồi add nó vào máy server. Cũng khá đơn giản, bắt đầu nhé.
Thao tác trên máy local: bật gitbash
, chạy command sau. Thoải mái thay đổi tên file deployerkey
nhé.
$ ssh-keygen -t rsa -b 4096 -f ~/.ssh/deployerkey
Copy đoạn public key hiện ra ở câu lệnh dưới đây:
$ cat ~/.ssh/deployerkey.pub
Thao tác trên máy server: Paste đoạn public key vừa copy vào server bằng các bước dưới đây:
$ nano ~/.ssh/authorized_keys
Dán public key vào editer và bấm CTRL-X
, Y
, rồi bấm ENTER
để lưu và thoát.
Giới hạn quyền đọc ghi của file authorized_keys
:
$ chmod 600 ~/.ssh/authorized_keys
NOTE: Nếu không Giới hạn quyền đọc ghi của file
authorized_keys
sẽ gặp lỗi: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
Bây giờ máy local của bạn đã có thể kết nối đến máy server rồi. Không tin thử xem:
$ ssh deployer@your_server_ip -i ~/.ssh/deployerkey
Phùzz, mệt chưa các bạn? Uống cốc trà rồi vào bước cấu hình Nginx
và MySQL
trên máy server nhé.
Bước 4 — Cấu hình Nginx
Đoạn cấu hình Nginx
này có thể tách riêng thành 1 bài kha khá chữ, nhưng mình vẫn viết vào đây, vì cấu trúc thư mục của Laravel với deployer nó hơi khác một chút.
Các thao tác dưới đây đều thực hiện ở máy server
Đầu tiên, chúng ta cần tạo một server block configuration file
cho website mới.
Đăng nhâp vào máy server với user có quyền sudo và tạo một file config mới. Lưu ý example.com
thay bằng domain của bạn nhé:
$ sudo nano /etc/nginx/sites-available/example.com.conf
Thêm đoạn cấu hình sau vào file example.com.conf
:
# example.com ’>/etc/nginx/sites-available/example.com.conf
server {
listen 80;
listen [::]:80;
root /var/www/html/laravel-app/current/public;
index index.php index.html index.htm index.nginx-debian.html;
server_name example.com www.example.com;
}
listen
2 dòng này báo vớiNginx
port nào web sẽ nhậnroot
chỉ ra đường dẫn đến source code.
Đường dẫncurrent/public
thực ra là mộtsymbolic link
trỏ đếnlatest release
của ứng dụng Laravel.index
chỉ ra thứ tự ưu tiên đọc file mặc định của Ngnix, ở đây là ưu tiên đọc fileindex.php
trước.server_name
chỉ ra domain của ứng dụng
Tiếp theo, cần chỉnh sửa file này thêm để Nginx có thể handler được các requests đến.
try_files
Chúng ta muốn server thử khớp các$uri
, đầu tiên là đúng chính xác, nếu không đúng, thử tiếp với index file của thư mục khớp với request ($uri/
), nếu vẫn không khớp, thử tiếp với index.php kèm theo query parameter:/index.php?$query_string
Sửa file example.com.conf
:
# example.com ’>/etc/nginx/sites-available/example.com
server {
listen 80;
listen [::]:80;
root /var/www/html/laravel-app/current/public;
index index.php index.html index.htm index.nginx-debian.html;
server_name example.com www.example.com;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$
block này xử lý việc thực hiện các file PHP. Điều này sẽ áp dụng cho bất kỳ tệp nào kết thúc bằng .php. Nó sẽ tự thử tệp và sau đó thử chuyển nó dưới dạng tham số cho tệp index.php.fastcgi
để báo cho Nginx sử dụng đường dẫn thực tế (actual path
) thay vìsymbolic link
. Nếu bạn không thêm các dòng này vào cấu hình, đường dẫn nơi các điểmsymbolic link
trỏ tới sẽ được lưu vào bộ đệm, nghĩa là một phiên bản cũ của ứng dụng của bạn sẽ được tải sau khi deploy. Nếu không có các cấu hình này, bạn sẽ phải xóa bộ nhớ cache bằng tay sau mỗi lần deploy và các requests đến ứng dụng của bạn có thể bị lỗi.fastcgi_pass
sẽ đảm bảo rằng Nginx sử dụng pluginphp7-fpm
để kết nối và file index.php được sử dụng làm index.
Cuối cùng, chúng ta cần đảm bảo rằng Nginx sẽ không cho phép access file ẩn .htaccess
qua block: location ~ /\.ht
. File hoàn chỉnh bên dưới:
# example.com ’>/etc/nginx/sites-available/example.com.conf
server {
listen 80;
listen [::]:80;
root /var/www/html/laravel-app/current/public;
index index.php index.html index.htm index.nginx-debian.html;
server_name example.com www.example.com;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
Lưu lại (CTRL-X, Y, rồi ENTER) và enable server block mới tạo bằng cách tạo symbolic link đến folder sites-enabled
$ sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/
Kiểm tra xem cấu hình ok chưa?:
$ sudo nginx -t
Nếu không có lỗi, restart Nginx để xem thay đổi:
$ sudo systemctl restart nginx
Vậy là chúng ta đã cấu hình xong Nginx, tiếp theo là cấu hình MySQL
Bước 5 — Cấu hình MySQL
Sau khi cài đặt, MySQL sẽ tạo một root
user mặc định. Đây là user có quyền tối thượng, nên dùng luôn user này mà cấu hình vào ứng dụng thì sẽ là một bad security practice
. Thay vào đó chúng ta sẽ tạo ra một database
mới và một user mới tương ứng với nó. Bắt đầu nhé.
Thao tác trên máy server: Đăng nhập vào MySQL console với quyền root:
$ mysql -u root -p
Nó sẽ hỏi mật khẩu, nếu mà lúc cài MySQL bạn không cấu hình thì mặc định là rỗng.
Tạo mới database:
mysql> CREATE DATABASE laravel_database DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Sau đó tạo mới database user
, tùy chỉnh password
ở dưới nhé.
mysql> CREATE USER 'laravel_user'@'localhost' IDENTIFIED BY 'password';
Gán quyền cho user tương ứng với database vừa tạo:
mysql> GRANT ALL ON laravel_database.* TO 'laravel_user'@'localhost';
Tiếp theo, reload quyền:
mysql> FLUSH PRIVILEGES;
Và cuối cùng, thoát SQL console:
mysql> EXIT;
Bây giờ Server đã cấu hình xong, chúng ta có thể sẵn sàng cho lần phóng tàu đầu tiên. Ahi.
Bước 6 — Deploy ứng dụng
Đến bước này chúng ta đã cài đặt và cấu hình gần đủ các thứ cần thiết để Deploy rồi. Chúng ta sẽ tạo ra một kịch bản deploy để Deployer
đọc và thực hiện theo.
Bắt đầu quá trình deploy nhé.
Thực hiện trên máy local Mở gitbash
tại folder code đã push lên Github ở Bước 2:
Ở folder này, chạy câu lệnh dưới đây để tạo ra file deploy.php
. Đây chính là file kịch bản phóng tàu mà Deployer
sẽ đọc để thực hiện.
$ dep init -t Laravel
Tiếp theo, mở file deploy.php
bằng text editor
mà bạn yêu thích. Ở đây mình dùng Visual Studio Code :
# deploy.php
<?php
namespace Deployer;
require 'recipe/laravel.php';
. . .
Chúng ta cần chỉnh sửa lại cấu hình ở một số trường dưới đây:
// Project Name
Tên dự án web của bạn.// Project Repository
Link project github của bạn. Lưu ý trong hướng dẫn này là linkssh
chứ không phảihttps
nhé.// Hosts section
Địa chỉ IP của máy server, hoặc domain cũng được. Kèm theo đó làDeployer user
(trong ví dụ này làdeployer
) . Đồng thời add thêm đường dẫn đến filessh key
đã tạo ở bước 3.3
Ok, cấu hình xong thì file nó sẽ như thế này:
# deploy.php
...
// Project name
set('application', 'laravel-app');
// Project repository
set('repository', 'git@mygitserver.com:username/repository.git');
. . .
// Hosts
host('your_server_ip')
->user('deployer')
->identityFile('~/.ssh/deployerkey')
->set('deploy_path', '/var/www/html/laravel-app');
Tiếp theo, comment out dòng này lại (dòng cuối của file), before('deploy:symlink', 'artisan:migrate')
;. Dòng này chỉ thị Deployer chạy migrate database
tự động. Chúng ta comment lại để disable tác vụ này. Nếu không comment lại deploy sẽ lỗi đấy, không tin thử mà xem :p:
# deploy.php
...
// Migrate database before symlink new release.
//before('deploy:symlink', 'artisan:migrate');
Cuối cùng, thử phóng tàu bằng command dưới đây nhé:
$ dep deploy
Oh, Something went wrong!
TTY mode is not supported on Windows platform.
Quay lại file deploy.php
thấy dòng set('git_tty', true);
, sửa lại thành false
rồi thử lại nhé.
set('git_tty', false);
Ơn giời, cậu xong rồi :D:
Ah, vẫn chưa xong, còn cấu hình file .env nữa.
Đăng nhập lại vào máy server để xem các file đã đẩy lên tự động với
cấu trúc như thế nào nhé: Mở gitbash
từ máy local để login cho đúng user deployer
.
Tránh đăng nhập lại bằng
root
, sẽ ảnh hưởng đến permission các file màdeployer
đang quản lý.
$ ssh deployer@your_server_ip -i ~/.ssh/deployerkey
Kiểm tra các thư mục có trong folder source đã upload lên:
$ ls -la /var/www/html/laravel-app
# Output
total 20
drwxr-xr-x 5 deployer nginx 4096 Jan 3 10:03 .
drwxr-xr-x 4 root root 4096 Jan 2 19:51 ..
lrwxrwxrwx 1 deployer deployer 10 Jan 3 10:03 current -> releases/1
drwxrwxr-x 2 deployer deployer 4096 Jan 3 10:03 .dep
drwxrwxr-x 3 deployer deployer 4096 Jan 3 10:02 releases
drwxrwxr-x 3 deployer deployer 4096 Jan 3 09:43 shared
Cấu trúc:
├── .dep
├── current -> releases/1
├── releases
│ └── 1
└── shared
├── .env
└── storage
Hiện tại ứng dụng của chúng ta vẫn chưa chạy, bởi vì file .env
đang trống. File này chứa các thông tin nhạy cảm như database
, api key
, email config
, nên không được push lên git (đã có trong .gitignore). Vì vậy chúng ta phải cấu hình bằng tay file này ở lần đầu deploy hoặc ở các deploy có thay đổi cấu hình trong .env
. Cũng vì chưa có file này nên chúng ta mới bỏ qua database migrations
ở bước trước đó.
Chạy command dưới đây trên server và copy nội dung file .env dưới máy local, paste vào và lưu lại:
$ nano /var/www/html/laravel-app/shared/.env
Trước khi lưu, bạn cần lưu ý các thông tin sau sẽ thay đổi so với local:
- APP_ENV=production
- APP_DEBUG=false
- APP_LOG_LEVEL=error
- Cập nhật lại thông tin DB_CONNECTION
Bạn có thể đổi example.com bằng domain của mình:
# /var/www/html/laravel-app/shared/.env
APP_NAME=Laravel
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_LOG_LEVEL=error
APP_URL=http://example.com
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_database
DB_USERNAME=laravel_user
DB_PASSWORD=password
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
Lưu file và đóng editor lại.
Bây giờ bạn có thể uncomment dòng cuối cùng của file deploy.php
trên máy local và deploy lại:
# deploy.php
...
// Migrate database before symlink new release.
before('deploy:symlink', 'artisan:migrate');
Warning: Bỏ comment dòng trên nghĩa là mỗi lần deploy thì database sẽ migrate lại. Vì vậy, những lần deploy sau thì comment lại nhé.
Ok rồi, thử phóng tàu lại lần nữa nhé:
Done rồi nha: (đoạn example.com chạy được là do mình đã sửa file hosts
trỏ đến ip của máy server)
Bước 7 — Thử deploy một tính năng mới xem sao
Đến đây là việc deploy tự động đã hoàn tất rồi. Mình thử test sửa cái tiêu đề "Laravel" rồi deploy lại nhé:
# resources/views/welcome.blade.php
...
<title>Haposoft Laravel Development Team</title>
...
<div class="title m-b-md">
Welcome to Haposoft Laravel Development Team
</div>
...
Lưu lại, rồi push lên github
, sau đó chạy lệnh deploy
, sẽ thấy kết quả:
$ dep deploy
Kết: Các bạn cứ thử theo các bước trên, gặp lỗi gì thì comment vào bên dưới xem mình đã gặp chưa nhé :)
Bài này hơi dài, các bạn có thể đọc và chia nhỏ từng phần để thực hiện.
Thank you all <3