Deploy React App với Apache Httpd Server Container (Dockerize)
Mở đầu
Chào mọi người, chuyện là ở công ty, mình được giao deploy 1 dự án có thành phần Front end module được code bằng React App. Thông thường mình sẽ deploy nó với Nginx container như cách truyền thống, tuy nhiên lần này, dự án được 1 anh Senior của công ty (hiện đã out project) đề xuất trước với khách hàng dùng Apache Server để triển khai. Và đến hạn release bọn mình cũng không thể đề xuất thay đổi được.
Để giảm effort cho việc tạo tài liệu Deployment Guideline cho khách, cũng như giảm độ phức tạp trong quá trình deploy thông thường (cài đặt NodeJS, cài đặt Apache Server, npm install, npm build.... ). Mình đã đề xuất deploy system dưới dạng containers nhưng vẫn dùng apache server để host React App dưới dạng static web app.
Cấu trúc dự án
Dự án gồm 4 modules chính:
- Microsoft SQL Server (customer side DB).
- MySQL (local DB).
- Spring Boot API Server.
- ReactJS Application.
Files
Phần source code của dự án, mình chia các modules thành các folder riêng để quản lí:
└── PROJECT
├── frontend-demo
├── backend
├── db
├── mysql
└── mssql
├── docker-compose.yml
└── .....
React App File structures
Bên trong thư mục frontend-demo, mình tạo riêng 2 file cấu hình phục vụ cho việc triển khai Apache Httpd Server.
- httpd.conf
- .htaccess
└── frontend-demo
├── public
├── src
├── index.html
├── package.json
├── vite.config
├── Dockerfile
├── httpd.conf
├── .htaccess
└── .....
httpd.conf
Tương đối giống với nginx.conf file, nếu bạn đã làm việc với Nginx rồi thì với Apache cũng tương tự. Chúng ta custom cấu hình Apache server bằng việc overwrite file httpd.conf này. Cụ thể, mọi người có thể overwrite lại các phần quan trọng như sau:
- Bên trong httpd.conf, tìm đến và uncomment dòng LoadModule sau để enable mod_rewrite, mặc định mod_rewrite được disable bởi Apache.
#LoadModule rewrite_module modules/mod_rewrite.so #xóa dấu '#' đi
- Tiếp tục chỉnh sửa dòng AllowOverride sau, đổi từ None sang chế độ All để cho phép ta override cấu hình.
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
Options Indexes FollowSymLinks
AllowOverride All #None -> All
Require all granted
</Directory>
- Save cấu hình này lại, để dành lúc chạy docker build, file này sẽ ghi đè nội dung xuống file httpd.conf của Apache container.
.htaccess
.htaccess (hypertext access) được dùng để cấu hình thêm các tính năng mà bạn mong muốn cho Apache Server. Với nó, bạn có thể cấu hình rewrite URL, password-protect directories, enable hotlink protection, disallow 1 IP nào đó, thay đổi website zone hoặc path đến file index.html ở directiory khác và còn nhiều hơn thế nữa.
- Save file với nội dung sau:
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule . /index.html [L]
- Đối với React sẽ là single page, tức là chỉ có 1 route duy nhất để hiển thị toàn bộ app. Với cấu hình như trên apache sẽ tự động truyền path cũng như param đến React App theo logic router đã code. Nếu không config mục này, Apache sẽ đi tìm các pages tương xứng với url và hiển thị trang trắng - error mặc định.
Dockerfile
Sau khi đã chuẩn bị 2 files: httpd.conf và .htaccess xong xuôi. Chúng ta cần soạn thảo lại nội dung Dockerfile bên trong folder Frontend code như sau:
FROM node:18-alpine as build-stage
WORKDIR /app
COPY package.json /app/package.json
RUN npm i
COPY . /app/
ARG VITE_BASE_URL
ENV VITE_BASE_URL $VITE_BASE_URL
RUN npm run build
# production stage with Apache httpd
FROM httpd:2.4.57-alpine as production-stage
COPY --from=build-stage /app/httpd.conf /usr/local/apache2/conf/httpd.conf
COPY --from=build-stage /app/dist /usr/local/apache2/htdocs/
COPY --from=build-stage /app/.htaccess /usr/local/apache2/htdocs/
Giải thích: Với cấu hình trên ta đã thực hiện
- Copy ghi đè httpd.conf của ta vào file cấu hình của Apache tại directory:
/usr/local/apache2/conf/httpd.conf
- Copy file .htaccess vào directory
/usr/local/apache2/htdocs/
File index.html sau khi build code cũng ở tại directory này, Apache sẽ đọc trực tiếp file index.html và truy cập các file trong thư directory trên.
VITE_BASE_URL là biến môi trường được thiết lập dynamic, tại đây nó là giá trị backend API server endpoint dùng để fetch API.
- Apache container mặc định đã được thiết lập start Apache server ngay khi khởi chạy container qua lệnh
httpd -D FOREGROUND
. Chúng ta không cần chỉ dẫn thêm run command trong Dockerfile như Nginx.
docker-compose.yml
Cuối cùng, để khởi chạy quá trình deploy cả hệ thống, ta biên soạn 1 file docker-compose.yml để start cùng lúc các services với nhau, tại file trên mình khai báo trực tiếp URL backend, folder source code, port mapping,...
version: '3.8'
services:
mysql: ...
mssql: ...
backend: ...
frontend:
container_name: frontend
build:
context: ./frontend-demo
args:
- VITE_BASE_URL=http://localhost:8080
ports:
- 80:80
depends_on:
- backend
Deploy commands
- Để deploy cả system gồm 4 servies, ta mở terminal tại thư mục PROJECT - nơi chứa file docker-compose.yml và nhập lệnh cmd sau:
docker compose up -d
hoặcdocker-compose up -d
docker-compose đã được thiết lập để khởi chạy theo thứ tự MSSQL -> MySQL -> Backend-> Frontend
- Để deploy chạy từng service một (ex: only frontend), ta nhập lệnh:
docker compose up frontend -d
hoặc mở terminal tại folder frontend, chạy lệnhdocker build -t frontend --build-arg VITE_BASE_URL=http://localhost:8080 .
sau đódocker run --name frontend -p 80:80 -d frontend
Testing
- Sau cùng, open browser với URL
http:localhost
(mình đang chạy ở port 80) để kiểm tra giao diện.
- Navigate đến các page khác của trang web, F5 refresh lại để chắc rằng nó vẫn load đúng trang.
- Nhập 1 trang lỗi bất kì ngoài các Route đã khai báo để chắc nó sẽ load đến trang Error Page bạn đã code.
Kết
Chúc mọi người thành công, nếu còn điều gì chưa hiểu hoặc có lỗi xảy ra, mọi người có thể để lại comment và feedback lại bên dưới. Thân.
PROJECT DEMO: Gitlab demo link
All rights reserved