Categories
DevOps

WEBSOCKET: TỪ SOCKETIO ĐẾN SOKETI

Khoảng 8 năm trước, từ lúc bỏ mô hình Server Side Rendering (jQuery, Ajax…) và bắt đầu xây dựng hệ thống dựa trên mô hình Microservices & Single Page App (SPA) và sử dụng hoàn toàn frontend bằng Reactjs thì cũng là lúc bắt đầu chơi với WebSocket cho các tính năng tương tác hai chiều (Client < — > Server) theo thời gian thực.

Hoạt động của WebSocket khá đơn giản: trình duyệt kết nối tới một Socket server, lắng nghe trên 1 (hoặc nhiều) channel mình khai báo rồi…chờ message trên channel đó. Server muốn gửi dữ liệu cho trình duyệt của user thì chỉ cần đẩy message vào channel này, trình duyệt sẽ tự động nhận message và xử lý (ví dụ như hiển thị thông báo trên trình duyệt hoặc một hành động khác.)

Nhiều người khi nghe nói đến Websocket thì chỉ nghĩ đến các tính năng realtime chat, nhưng Websocket có nhiều ứng dụng, trong đó mình sử dụng nhiều nhất cho 3 chỗ trên trình duyệt: Nhận thông báo mới (Notification), Cập nhật dữ liệu cache trên trình duyệt (Realtime Data Update) và Trạng thái online của user (Online Presence).

Các phần mềm hỗ trợ WebSocket Server

Thời bấy giờ không có nhiều lựa chọn, ứng cử viên sáng giá nhất là Socket.IO: Open Source – Miễn phí, tự cài đặt trên server riêng và Pusher: Cloud, không cần cài đặt gì hết và trả phí.

Socket.IO thì hầu như không có nhiều đồ chơi, ngoài việc chỉ hỗ trợ trình duyệt kết nối socket tới server, không có cơ chế xác thực (Authentication), muốn làm gì thì phải chủ động code tính năng hết. Do mình làm ứng dụng cho dự án SaaS và multi-tenant nên khối lượng code viết thêm nếu làm trên SocketIO là quá lớn nên buộc phải tìm giải pháp khác, và lúc này Pusher đã xuất hiện.

Pusher cung cấp cơ chế WebSocket với nhiều tính năng, trong đó có 2 tính năng nổi bật nhất là hỗ trợ Authentication xác thực user kết nối và Presence Channel để biết ai đang online/offline. Ngoài ra, Pusher còn cung cấp các thư viện tích hợp cho cả Javascript (gắn ở trình duyệt) và PHP (gắn ở server) để xác thực và trao đổi dữ liệu realtime giữa client và server được đơn giản và nhanh chóng, rút ngắn thời gian phát triển.

Có một bất lợi duy nhất của Pusher là…chi phí. Do đặc thù của một hệ thống Realtime là số lượng kết nối thường xuyên đến socket server, nên chi phí tính dựa vào số lượng kết nối. Sau khi đánh giá thì với chi phí của Pusher so với những lợi ích nó mang lại thì quyết định chọn Pusher.

Thay thế Pusher bằng Soketi

Mười ngày trước, nằm trong tuần lễ cải tổ hệ thống, trong đó có hạng mục nâng cấp phân hệ Pusher sau một thời gian dài sử dụng, thì thấy chi phí hiện tại không ổn nếu scale lên vài ngàn socket connection dựa trên Pusher, cũng như áp dụng cho các khách hàng outsourcing.

Thật may mắn là đã tìm ra Soketi, một open source cài đặt trên server của mình và cung cấp các tính năng gần như tương tự của Pusher. Và đặc biệt quan trọng là tương thích hoàn toàn với các thư viện kết nối ở phía Javascript và PHP, tức là không phải thay đổi cơ chế kết nối và lắng nghe message, chỉ cần cài Soketi (có hỗ trợ docker), sau đó thì config trỏ lại kết nối đến Soketi Websocket server vừa cài là xong.

Sau một tuần triển khai lên các môi trường dev và production cho các dự án thì thấy hoàn toàn ổn định, kết quả này cũng là cảm hứng cho bài viết chia sẻ công nghệ này. Hy vọng anh chị em có một hệ thống Websocket ngon, bổ rẻ để xây dựng các tính năng realtime cho môi trường web.

Categories
Technology

Vũ trụ Nextjs và Headless CMS

Sau nhiều ngày chờ đợi để xem NextJS có ra bản 13.5 hay không thì cũng không chịu được nữa (nằm ở v13.4 đã gần 3 tháng) và đành khởi công dự án xây dựng Public CMS Framework (hay nói kiểu nhà quê là làm cái website) với phiên bản NextJS 13.4.12.

Server Side Rendering (SSR) với PHP

#Cropcom, mỗi một Public CMS Framework được xây dựng thì xác định tối thiểu phải 5 năm sau mới thay đổi công nghệ nên việc lựa chọn công nghệ nền ban đầu ảnh hưởng rất lớn đến trải nghiệm phát triển tính năng của team, cũng như phải “chịu đựng” trong quá trình xây dựng tính năng nếu lỡ nó lạc hậu hoặc team đó bỏ rơi không phát triển tiếp công nghệ nền.

Nếu bạn quan tâm thì Public CMS Framework gần nhất của công ty do Tuấn xây dựng là dựa trên PHP 7, sử dụng một phần của Symfony HTTPFoundation để xây dựng core, sử dụng Smarty cho tầng View (HTML, CSS..), còn layer Model & Controller thì kết nối đến hệ thống microservice theo cơ chế Headless CMS. Public CMS này thực ra hiện tại vẫn ổn vì nó tương thích hoàn toàn với khả năng Server Side Rendering (SSR) để tận dụng tối đa khả năng onsite SEO.

NextJS cho SSR & CSR trong tương lai

Hướng cũ này có một bất lợi duy nhất là, sẽ khó khăn nếu tiếp cận xây dựng các tính năng không cần SEO (sau màn hình đăng nhập) như thông tin tài khoản, các tính năng sau khi đăng nhập (submit này nọ, tương tác với thành viên khác…). Lỡ theo kiến trúc này nên phần lớn các tính năng đòi hỏi thuần Client Side Rendering (CSR) toàn phải xài jQuery và code chay, rất khó mở rộng theo nhánh này. Mà ngày nay, làm gì có website nào chỉ thuẩn SEO content, nếu vậy xài WordPress cho rồi, viết framework đồ chi.

Nếu muốn viết lại Framework mới cho Public CMS thì phải giải quyết được 2 bài toán là cần có SSR, hỗ trợ được các công nghệ CSR như Reactjs…để vừa đạt hiệu quả làm SEO, vừa hỗ trợ team dev phát triển tính năng một cách hiệu quả, nhanh chóng. Thế là đến với NextJS. Hiện tại sau hơn 4 năm chạy với Nextjs (từ nextjs 8.x đến nay thì phiên bản 13.4 được coi là siêu ổn để giải quyết 2 vấn đề lớn mà Tuấn cần giải quyết cho Public CMS của mình.

Lựa chọn UI Component Library

Tuy nhiên, sau khi trào lưu di dời sang Nextjs thì sẽ phát sinh 1 vấn đề khác là không có một bộ Component UI Library hoàn hảo. Và vấn đề này luôn là mối quan ngại khi xây dựng CMS với Nextjs bởi chưa có “cái nào” mà mình đánh giá là xài được. Radix UI thì có vẻ phức tạp, ngôi sao mới nổi Shadcn thì tạo ra các giao diện không mấy thân thiện với người dùng bình thường nên chủ yếu shadcn để xây các sản phẩm hơi hướng tinh giản và tech savy. Chưa kể nhiều UI Lib không tương thích với React Server Component.

Dường như vũ trụ Nextjs đã lắng nghe, và sau 1 ngày xây dựng thì dự án NextUI (không liên quan đến Vercel) hôm qua đã ra mắt phiên bản 2.0 với RẤT nhiều cải tiến mà sẽ dùng tốt cho NextJS 13 (dùng App Router). Việc thấy được sự ra mắt của NextUI 2.0 chính là cảm hứng cho mình chia sẻ bài viết này cũng như mọi người có thể hình dung xây dựng một Public CMS cần có nhiều yếu tố cân nhắc vì tính dài hạn và hướng người dùng (UX) & hướng dev (DX).

NextUI Website: https://nextui.org/

Trong tương lai nếu có lib nào xịn hơn thì sẽ xem xét và cân nhắc, nhưng cho đến hôm nay thì mình thấy NextUI là chân ái và sẽ apply cùng với TailwindCSS cho toàn bộ các design của CMS.

Categories
DevOps

Speed up Microservices 3: Export dữ liệu ra Excel

Chào mọi người, nối tiếp bài trước là tận dụng caching ở trình duyệt để tăng tốc cho microservices. Ở bài này mình sẽ chia sẻ một case study khá thông dụng trong các dự án “vừa vừa”, đó là nhu cầu export dữ liệu ra file excel. Nếu như các bạn thường xuyên làm việc liên quan đến các hệ thống quản lý dữ liệu thì data table / grid sẽ xuất hiện khá nhiều, kéo theo tính năng thường xuyên được yêu cầu là export dữ liệu (ra file Excel).

Categories
DevOps

Triển khai CI/CD với Gitlab 9

Cũng hơn một tháng kể từ bài viết gần nhất, nay mới có thời gian ngồi viết lách tiếp. Dạo gần đây thường release các dự án outsource nên cũng hay làm documentation cũng như  mở các dự án mới nên việc setup CI/CD thường xuyên hơn và chân tay hơn. Thấy các kiến thức này hay nên hôm nay mình sẽ chia sẻ mọi người quy trình CI/CD bên mình áp dụng cho “đại dự án” Teamcrop cũng như các dự án outsourcing mà Moout thực hiện.

CI/CD là gì?

Bạn sẽ thấy có nhiều định nghĩa từ hai lúa cho đến hàn lâm cho khái niệm CI/CD. Mình sẽ dùng cách định nghĩa của mình để mọi người dễ hiểu theo cách thông thường nhất. CI/CD là một bộ đôi công việc, bao gồm CI (Continuous Integration) và CD (Continuous Delivery), ý nói là quá trình tích hợp (integration) thường xuyên, nhanh chóng hơn khi code cũng như thường xuyên cập nhật phiên bản mới (delivery).

Tại sao phải quan tâm đến CI/CD?

Ngày nay, với xu hướng agile/lean dẫn đến việc phát triển tính năng là điều bình thường, quan trọng phải là thần thái, ý lộn, quan trọng là phải nhanh. Nếu một tính năng mà mất 2, 3 tháng mới release thì dẫn đến nhiều hệ lụy như làm không phù hợp nhu cầu khách hàng, hoặc đối thủ đã ra mắt trước đó, mất đi cái lợi thế dẫn đầu. Do đó, việc làm ra một sản phẩm, tính năng đòi hỏi thần tốc là ưu tiên số một hiện nay.

Bên cạnh đó, để nhanh chóng ra mắt một tính năng, phiên bản mới nếu theo cách cổ điển sẽ mất nhiều thời gian bởi công việc chân tay khá nhiều và mỗi lần release cũng huy động một cơ số người không nhỏ để cập nhật một thay đổi dù là nhỏ nhất. Bởi vậy, xu hướng CI/CD giúp cung cấp các framework, workflow giúp tiết kiệm thời gian, nguồn lực của quá trình release (delivery).

Quy trình CI/CD tham khảo

Có rất nhiều quy trình, công cụ khác nhau để ứng dụng CI/CD vào dự án. Nội dung của bài viết này dựa trên kinh nghiệm cho các dự án của mình triển khai cũng như đặc thù là các hệ thống web, và viết bằng PHP (PHP hoặc Python hoặc abc…không quá quan trọng trong ngữ cảnh chia sẻ về CI/CD).

Dưới đây là các bước thông thường của quá trình release tính năng trong một dự án thuộc hệ thống Teamcrop.
Bước 1: [Manual] Khởi tạo repository và có branch default là master và dev. Cài đặt trên Gitlab 9.
Bước 2: [Manual] Trừ owner ra, thì các coder sẽ push code tính năng lên branch dev
Bước 3: [Auto] Hệ thống tự động thực hiện test source code, nếu PASS thì sẽ deploy tự động (rsync) code lên server beta.
Bước 4: [Manual] Tester/QA sẽ vào hệ thống beta để làm UAT (User Acceptance Testing) và confirm là mọi thứ OK.
Bước 5: [Manual] Coder hoặc owner sẽ vào tạo Merge Request, và merge từ branch dev sang branch master.
Bước 6: [Manual] Owner sẽ accept merge request.
Bước 7: [Auto] Hệ thống sẽ tự động thực hiện test source code, nếu PASS sẽ enable tính năng cho phép deploy lên production server.
Bước 8: [Manual] Owner review là merge request OK, test OK. Tiến hành nhấn nút để deploy các thay đổi lên môi trường production.
Bước 9: [Manual] Tester/QA sẽ vào hệ thống production để làm UAT và confirm mọi thứ OK. Nếu không OK, Owner có thể nhấn nút Deploy phiên bản master trước đó để rollback hệ thống về trạng thái stable trước đó.
Bước 10: [Manual] Thắp nhang và hy vọng khách hàng không chửi rủa hoặc email complain.

Áp dụng CI/CD với Gitlab 9

Trong khuôn khổ bài viết này, mình sẽ hướng dẫn mọi người cài đặt Gitlab 9 để quản lý source code, và trên công nghệ Git. Đòi hỏi của tất cả setup này là trên server đã cài Docker, nếu các bạn chưa có docker trên server thì có thể tham khảo các bài viết về docker trên bloghoctap cũng như tìm kiếm thêm trên google.

Tại sao phải là Gitlab 9?

Đây là câu hỏi hay, bởi vì trước đó bên mình sử dụng Gitlab 8, tuy nhiên, do các hạn chế về UI/UX cũng như không tích hợp ngon lành vụ CI/CD nên khi bản 9 ra mắt, mình đã thử sử dụng và thấy bản 9 phù hợp hơn cho workflow nên quyết định dọn dẹp sang Gitlab 9.

Cài đặt Gitlab 9 với docker

Bạn chạy câu lệnh sau để tạo một container chứa Gitlab 9.

docker run --detach \
    --hostname code.teamcrop.com \
    --publish 8080:80 --publish 2222:22 \
    --name gitlab9 \
    --restart=always \
    --volume /gitlab9/config:/etc/gitlab \
    --volume /gitlab9/logs:/var/log/gitlab \
    --volume /gitlab9/data:/var/opt/gitlab \
    gitlab/gitlab-ce:9.0.3-ce.0

Nếu ai từng dùng docker sẽ hiểu ý nghĩa câu lệnh trên. Đơn giản là mình sử dụng image gitlab/gitlab-ce:9.0.3-ce.0. Có mount ra 3 thư mục bên ngoài máy ở thục mục /gitlab9 để lỡ có chuyện gì chỉ cần stop, remove container, khi chạy docker run lại thì không bị mất dữ liệu, source code. Câu lệnh trên có map 2 port là 8080 và 2222 tương ứng tới 2 port 80 và 22 trong container. Mình mapping port vậy bởi vì trên server dev này có rất nhiều service khác và đã chiếm port 80 và 22 (ssh ^^!).

Sau khi bạn start container thì có thể truy cập vào từ ip hoặc domain (mà bạn đã trỏ DNS), ví dụ: http://code.teamcrop.com:8080 là có thể vào gitlab 9, tài khoản mặc định là `root`.

Không có gì cao siêu ở cài đặt này, có thể tham khảo thêm ở trang chủ của Gitlab.com nhé.

Quản lý sourcecode bằng Gitlab

Về phần này thì mình không cần nói dài dòng, cũng như một hệ thống git thông thường (như github..), bạn có thể tìm hiểu thêm về git và Gitlab để team có thể cùng làm việc và quản lý sourcecode trên Gitlab.

CI/CD với Gitlab CI

Thông thường, các hệ thống quản lý sourcecode không kèm theo cơ chế CI/CD. Nếu bạn muốn triển khai thì buộc phải liên kết đến repository, phân quyền đủ kiểu để hệ thống đó có thể lấy source code từ respository. Trước đây bên mình sử dụng Jenkins cho việc này. Tuy nhiên, từ khi Gitlab ra mắt tính năng Gitlab CI, kèm theo sự chậm chạp, rắc rối và rề rề của Jenkins thì mình quyết định chia tay với Jenkins và đến với Gitlab CI luôn, và quả là một bộ đôi hoàn hảo. Code để ở Gitlab, rồi trong đó có cho cài đặt CI/CD để test và deploy code tự động.

Cũng như một số bạn mới lần đầu tiếp xúc với Gitlab CI, mình đã từng thấy nó khó hiểu và cao siêu vì setup tùm lum. Rồi setup xong lại không biết nó chạy thế nào, cơ chế deploy source code ra sao. Tuy nhiên, sau một vài “va chạm” đầy mồ hôi và nước mắt thì cũng nắm và hiểu được cách Gitlab CI vận hành, và nay chia sẻ cho mọi người để vận dụng cho workflow của mình.

Để dùng được Gitlab CI thì bạn cần có 2 thành phần sau: file `.gitlab-ci.yml` nằm ở thư mục gốc của dự án và Gitlab Runner.

File .gitlab-ci.yml là gì?

Mặc định Gitlab không có cơ chế nào về CI cho dự án của bạn, chỉ khi nào dự án của bạn có file .gitlab-ci.yml nằm ở thư mục gốc thì Gitlab mới nhận dạng được dự án của bạn muốn áp dụng Gitlab CI. File này có định dạng và cần hợp lệ thì mới có thể hoạt động được, không thì khi bạn push code lên thì Gitlab sẽ báo lỗi file định dạng nội dung của file cấu hình không hợp lệ. Tham khảo cú pháp của cấu hình này tại https://docs.gitlab.com/ce/ci/yaml/

Trong file này có gì? File này có một số section để khai báo như trước khi chạy test thì làm gì, khi test thì thực hiện lệnh gì (vd chạy linter check cú pháp, chạy PHPUnit test…), test xong rồi thì thực hiện deploy đi đâu (beta, production..) với câu lệnh gì (vd: rsync..). Tùy đặc thù ngôn ngữ lập trình, cách đóng gói của dự án mà sẽ có các lệnh tương ứng thực hiện.

Tới đây các bạn sẽ có câu hỏi là vậy cái gì sẽ chạy, thực thi các câu lệnh, chỉ dẫn trong file config trên? Hay là Gitlab Server sẽ chạy. Nếu là Gitlab server chạy thì nếu dự án mình thực hiện những lệnh không có thì sao, vì gitlab server thì cũng chỉ chứa gitlab và các program cho nó chứ đâu thể cài sẵn các program? Bên cạnh đó, mỗi lần chạy thì các thông tin liên quan đến file tạm có bị reset lại hay không?

Nếu bạn đi đến đây thì bạn đã đoán được là thực ra “cái thứ” thực thi các chỉ dẫn, câu lệnh trong file .gitlab-ci.yml không phải là Gitlab Server (là cái container đang chạy gitlab 9 mình start ở trên), mà đó chính là Gitlab Runner. Wow! Welcome to matrix!

Gitlab Runner là gì?

Gitlab Runner là thành phần cực kỳ quan trọng trong workflow Gitlab CI. Nếu không có Runner thì sẽ không có lệnh test, deploy nào được thực thi. Runner có nhiều loại, phân biệt dựa vào cái gọi là executor. Khi khởi tạo runner, bạn sẽ phải chọn nó là loại executor nào, và nó sẽ quyết định môi trường thực thi các câu lệnh trong file config ở trên. Bạn có thể tham khảo link https://docs.gitlab.com/runner/executors/ để biết sự khác nhau của các executor cũng như cách cài đặt, cấu hình chúng.

Do đặc thù hệ thống đã có docker, nên bên mình chỉ sử dụng executor loại Docker mà thôi. Và bên dưới là câu lệnh docker để start một Gitlab Runner.

docker run -d --name gitlab-runner --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest

Ở đây bạn sẽ thấy container này mount thư mục config ra ngoài, bởi vì mình muốn các cấu hình của runner không bị mất khi stop/remove container. Chỉ cần start lại là giữ được cấu hình. Ngoài ra, nó còn mount docker.sock vào bên trong container, đây là cách để executor loại docker có thể tận dụng lệnh docker bên ngoài host để thực hiện lệnh tạo container phụ trong quá trình runner chạy (test, deploy).

Start container lên chỉ là bước đầu, bởi vì lưu ý là tới thời điểm này, Runner này không có liên quan gì đến Gitlab server của chúng ta. Cần một bước link lại (gọi là register) runner này vào trong Gitlab server để mình có thể cho phép các dự án dùng runner trong quá trình CI/CD.

Xem link này https://docs.gitlab.com/runner/register/index.html để biết cách register runner này vào Gitlab Server.

Dưới đây là hình ảnh tham khảo bạn có thể dùng trong quá trình register 1 runner. Có 2 thông tin quan trọng là 1 cái URL và một random token. Và cái URL đặc biệt lưu ý là thường thêm /ci sau domain. Ví dụ ở trường hợp của mình setup là http://code.teamcrop.com/ci

Sau khi Runner đã được gán vào Gitlab Server, bạn có thể enable runner này cho một hoặc nhiều dự án trong Gitlab. Hình bên dưới minh họa việc gán Runner vào dự án trong phần cài đặt Pipeline của Gitlab 9.

Đến đây hầu như đã cấu hình xong. Dự án đã kích hoạt 1 runner, và dự án đã có file .gitlab-ci.yml. Từ bây giờ, mỗi lần code được đưa lên thì runner sẽ thực thi test cũng như deploy dựa trên các câu lệnh được khai báo trong file cấu hình.

Khai báo biến để dùng trong các câu lệnh

Trong một số trường hợp, bạn có thể khai báo biến để có thể dùng trong các lệnh của runner. Có 3 nơi có thể cấu hình biến:
1. Cấu hình ngay bên trong file .gitlab-ci.yml
2. Cấu hình trong dự án. Vào Settings // CI/CD Pipelines, phần Secret variables (xem hình)

3. Cấu hình bên trong file config của runner. Bạn có nhớ lúc mình khởi tạo runner, có chỉ định một thư mục chứa config không, đây chính là nơi cấu hình chung cho runner này. Trong thư mục này sẽ có file là config.toml. Và bạn có thể gán biến trong cấu hình của từng runner. Cấu hình ở đây có một lợi thế là cứ runner này chạy sẽ nhận được biến đã cấu hình. Bạn không cần phải cấu hình nhiều lần ở từng dự án.

Ví dụ về một file .gitlab-ci.yml

Bên dưới là file cấu hình của một dự án trong hệ thống Microservices thuộc Teamcrop:

before_script:
- export "PATH=$PATH:/vendor/bin"
# Install ssh-agent if not already installed, it is required by Docker.
# (change apt-get to yum if you use a CentOS-based image)
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'

# Run ssh-agent (inside the build environment)
- eval $(ssh-agent -s)

# For Docker builds disable host key checking. Be aware that by adding that
# you are suspectible to man-in-the-middle attacks.
# WARNING: Use this only with the Docker executor, if you use it with shell
# you will overwrite your user's SSH config.
- mkdir -p ~/.ssh
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'

variables:
  # Change this base on project name
  DEPLOYMENT_FOLDER_NAME: "tc-file"

test:
  image: voduytuan/gitlab-php-ci
  script:
  - bash ./ci/phplint.sh ./src/
  - phpcs --config-set ignore_errors_on_exit 1
  - phpcs --config-set ignore_warnings_on_exit 1
  - phpcs --standard=PSR2 --ignore=./src/index.php --error-severity=1 --warning-severity=8 -w --colors ./src/
  - phpunit --configuration ci/phpunit.xml

dev:
  image: voduytuan/gitlab-php-ci
  stage: deploy
  script:
  - ssh-add <(echo "$DEPLOYER_BETA_KEY")
  - echo "Deploy to $DEPLOYMENT_FOLDER_NAME"
  - rsync -avuz -e "ssh -p 22" --exclude-from="ci/deploy_exclude.txt" $CI_PROJECT_DIR/src/ $DEPLOYER_BETA_USER@$DEPLOYER_BETA_IP:/teamcrop/services/$DEPLOYMENT_FOLDER_NAME/src
  only:
  - dev

production:
  image: voduytuan/gitlab-php-ci
  stage: deploy
  script:
  - ssh-add <(echo "$DEPLOYER_PRODUCTION_KEY")
  - echo "Deploy to $DEPLOYMENT_FOLDER_NAME"
  - rsync -avuz -e "ssh -p 22" --exclude-from="ci/deploy_exclude.txt" $CI_PROJECT_DIR/src/ $DEPLOYER_PRODUCTION_USER@$DEPLOYER_PRODUCTION_IP:/teamcrop/services/$DEPLOYMENT_FOLDER_NAME/src
  only:
  - master
  when: manual

Trong ví dụ trên, phần test bên mình làm 3 việc:
– Chạy linter để đảm bảo sourcecode không bị lỗi cú pháp (phplint)
– Kiểm tra source code có theo chuẩn PSR2 hay không.
– Chạy PHPUnit

Còn về phần deploy thì có cấu hình 2 task là deploy dev và production. Ở task dev thì auto và lấy code từ branch dev. CÒn task production deploy từ branch master, tuy nhiên, có chế độ deploy manual, tức là nhấn thì mới deploy.

Về phần deploy source code thì sử dụng rsync để đẩy code từ repo sang server. Bạn sẽ thấy cú pháp giống nhau, chỉ khác là cấu hình đẩy đi đâu, với user nào và private key nào.

Do đặc thù của commandline nên sử dụng privatekey để đồng bộ code thông qua rsync. Do đó, trong project mình có cấu hình privatekey của user. Và bên server nhận (beta, production) mình đã đưa public key vào file authorized_keys. Bạn có thể tìm hiểu thêm về setup và generate cặp public/private key cho user deploy để hỗ trợ quá trình này tại link https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys–2. Hay ngắn gọn là thực hiện câu lệnh “ssh-keygen -t rsa -C “[email protected]” -b 4096″, nhập vài thông tin là bạn đã có public key (id_rsa.pub) để đem bỏ lên server (beta, production) và private key (id_rsa) đem bỏ vào setting biến môi trường.

—-
Dựa trên những kinh nghiệm CI/CD cho hệ thống Teamcrop.com theo mô hình microservice với hơn 40 repository lớn nhỏ, hy vọng bài viết này sẽ giúp được cho quá trình setup CI/CD cho hệ thống của bạn, cũng như tăng tốc quá trình phát triển dự án. Nếu thấy bài viết hay và hữu ích, hãy chia sẻ cho các anh em khác để cùng trao đổi và giao lưu.

Categories
DevOps

Speed up Microservices 1: Tác dụng phụ và một số chiến lược cơ bản


Chào mọi người, nếu như các bạn cũng biết thì dự án Teamcrop của mình xây dựng và chạy hoàn toàn trên kiến trúc Microservices và sau hơn 2 năm triển khai thì có một số vấn đề liên quan đến kiến trúc này, thiết nghĩ cần chia sẻ thêm với mọi người để mọi người thấy được rằng Microservices không phải là chìa khóa vạn năng như vẫn hay nghe quảng cáo, dụ dỗ. Mọi kiến trúc đều có đánh đổi và Microservices cũng vậy.

Categories
Technology

Web Scalability 101: Biết giới hạn của hệ thống

scalability
Sau mấy tuần vật lộn với công việc sau Tết thì cũng có thời gian viết lách. Đây là bài viết về kỹ thuật đầu tiên của năm và là bài đầu tiên trong loạt bài chia sẻ về các chiến thuật scaling hệ thống web có tên là “Web scalability 101 (vỡ lòng)”.

Nếu quan tâm đến scale hệ thống, bạn có thể google những từ khóa liên quan đến scale, ngôn ngữ, công nghệ mà hệ thống bạn đang sử dụng, và phần lớn là các bài viết chỉ về các cài đặt, cấu hình cụ thể của một công nghệ nào đó như tùy chỉnh PHP thế nào, tùy chỉnh nginx, tùy chỉnh mysql ra sao…và có thể bạn sẽ lạc trong một mớ hỗn độn các kiến thức cấu hình này.

Categories
Technology Web Programming

Apitoy – Free Restful Documentation

Apitoy.com

Chắc hẳn là lập trình web thì mọi người đã từng một lần kết nối đến một hệ thống khác thông qua Web Service, có thể là SOAP, RESTful…Nội dung bài viết này mình sẽ chia sẻ với mọi người một số vấn đề và giải pháp mà mình đang gặp phải khi triển khai các Restful service.

Restful Documentation

Trong quá trình thiết kế Restful API, documentation (docs) cho API là một trong những thứ cực kỳ cần thiết để giúp bạn cũng như công ty, khách hàng dễ dàng làm việc trên API mà bạn thiết kế.

Docs API đơn giản có thể là các ghi chú, word, excel hoặc các SaaS base service để giúp tạo API nhanh chóng và tiện lợi hơn cũng như hỗ trợ làm việc nhóm hiệu quả hơn.

Đã thử dùng rất nhiều công cụ và nhiều phương tiện khác nhưng không có cái nào phù hợp nhu cầu nên đành tự phát triển một công cụ tạo docs API riêng cho mình, đơn giản và linh hoạt hơn, đó là Apitoy.com.

Cũng như hầu hết các công cụ SaaS based khác để làm Restful API Docs, Apitoy.com cũng cho phép tạo nhiều dự án, mỗi dự án sẽ có nhiều nhóm request (group). Mỗi request sẽ có quy định loại request (GET, POST, PUT..), tham số đầu vào, định dạng cũng như các thông tin request / response của một request.

Một số hình ảnh của Apitoy:

apitoy-zone
Danh sách Zone (Project)

Danh sách các Request của một zone.
Danh sách các Request của một zone.

Chỉnh sửa chi tiết một Request
Chỉnh sửa chi tiết một Request

Chi tiết một Request Docs
Chi tiết một Request Docs

Mock Server

Cũng như các lập trình viên thiết kế Restful API khác, việc dựng một Mock server từ một API Docs là một nhu cầu cực kỳ cần thiết để việc test cũng như tách biệt giữa web service consumer & service producer trong quá trình phát triển ứng dụng. Nhờ có Mock server mà phía frontend có thể có data giả (fake data) nhưng có cấu trúc đúng với cấu trúc của API thiết kế và sẽ không lệ thuộc vào backend phải hoàn thành API trước khi thử.

Apitoy có một tính năng rất thú vị và độc đáo là cho phép tự tạo một mock service dựa vào một request mà bạn đã thiết kế và response data (fake data) sẽ được auto-generate khi có request vào đúng mô tả request của bạn như đúng HTTP Method (GET, POST< PUT…), đúng URL…
Lưu ý là để mock service có thể chạy thì bạn bắt buộc phải tạo ít nhất 1 response cho request. Các snippet động “{{…}}” sẽ được bỏ khi xem docs và được thay thế khi có request để lấy mock data.

Apitoy hỗ trợ một số hình thức generate dữ liệu động sau:

Kiểu dữ liệu chuẩn

Nếu các giá trị có dạng “Integer”, “Float”, “String” thì sẽ được thay thế bằng các dữ liệu ngẫu nhiên tương ứng với kiếu giá trị như “100”, “3.14”, “Hello world”…

Faker Snippet

Apitoy có tích hợp thư viện https://github.com/fzaninotto/Faker để giúp bạn generate các dữ liệu ngẫu nhiên trông “thật” hơn ví dụ:

String{{phoneNumber}}: Thay thế bằng số điện thoại ngẫu nhiên
String{{email}}: thay thế bằng email ngẫu nhiên
Integer{{randomNumber}}: thay thế bằng một số ngẫu nhiên
Integer{{randomNumber:5}}: thay thế bằng một số ngẫu nhiên có 5 chữ số

Bạn có thể tham khảo website https://github.com/fzaninotto/Faker để biết tất cả các Snippet hỗ trợ trong Apitoy để generate các dữ liệu “giống thật” hơn.

Apitoy Snippet

Bên cạnh các snippet hỗ trợ từ thư viên Faker, apitoy còn cung cấp 2 snippet khác là “enum” và “repeat”.

– String{{enum:option1:option2:option3}}: chọn ngẫu nhiên một giá trị trong danh sách option. Ví dụ: Integer{{enum:0:1}}, String{{enum:”Yes”:”No”}}…

– {{repeat:repeat_id:repeat_count:repeat_seperator}}…{{/repeat:repeat_id}}: lặp lại một đoạn code được đánh dấu. Trong đó: “repeat_id” để đánh dấu đoạn code cần lặp, không có 2 đoạn repeat có cùng “repeat_id”. “repeat_count” số lần lặp lại của đoạn code bạn đánh dấu. “repeat_separator” ký tự phân cách giữa các lần lặp, mặc định là dấu phẩy “,”.

Ví dụ một đoạn code có đánh dấu cho Mock service:

{
    "total": Integer,
    "items": [
        {{repeat:item:2}}
        {
            "id": Integer{{randomNumber:5}},
            "internalid": String{{uuid}},
            "jobtitle": String{{sentence:3}},
            "phone": [
                {{repeat:phone:2}} String{{phoneNumber}} {{/repeat:phone}}
            ],
            "address": String{{streetAddress}},
            "isdeleted": Integer{{enum:0:1}},
            "datecreated": Integer{{unixTime}},
        }
        {{/repeat:item}}
    ]
}

Khi có request vào, server sẽ trả về dữ liệu sau:

{
    "total": 2834983,
    "items": [

        {
            "id": 86279,
            "internalid": "fa25b791-e185-37c1-8830-37ad177e6832",
            "jobtitle": "Nisi architecto laudantium aperiam.",
            "phone": [
                 "499.613.9008" , "(616)119-4152x20704" 
            ],
            "address": "730 Alene Wall",
            "isdeleted": 1,
            "datecreated": 264592903,
        }
        ,
        {
            "id": 90095,
            "internalid": "140abd91-3aba-3562-9dc1-d8f9ce275444",
            "jobtitle": "Tempore et ad quisquam.",
            "phone": [
                 "1-275-835-9601x690" , "05349335502" 
            ],
            "address": "796 Hauck Garden Suite 358",
            "isdeleted": 0,
            "datecreated": 364877373,
        }

    ]
}

——

Hy vọng bài viết này sẽ giúp các bạn có cái nhìn chi tiết hơn về cách triển khai một hệ thống Restful API.

Categories
Python

Download sách “Python rất là cơ bản”

python-co-ban

Hiện nay, Python là một trong những ngôn ngữ lập trình đang được chú ý bởi tính đa dạng về ứng dụng, thư viện phong phú và cộng đồng đông đảo.

Đã làm việc với PHP 10 năm, và có những tác vụ mà PHP khó mà thực hiện tối ưu được, khiến mình phải tiếp cận với Python trong giai đoạn này.

Cuốn sách nhỏ này được viết trong quá trình mình bắt đầu học Python và giải quyết các bài toán cơ bản theo nhu cầu của mình.

Hy vọng những ghi chép của mình cũng sẽ giúp ích cho những ai đang quan tâm đến việc ứng dụng Python vào công việc và xử lý hiện tại.

Mục lục

Sách được chia làm 15 chương, mỗi chương sẽ trình bày 1 khía cạnh của Python mà mình sẽ gặp phải và sẽ hữu ích khi biết các kiến thức này trong việc áp dụng Python vào công việc trong tương lai.

  1. Hello world
  2. Cú pháp
  3. Phân chia module
  4. Class
  5. Kết nối MySQL
  6. Kết nối Redis
  7. Kết nối Memcached
  8. Kết nối RabbitMQ
  9. Restful Client
  10. Thao tác trên tập tin
  11. Xử lý hình ảnh
  12. Xử lý file JSON
  13. Xử lý file XML
  14. Gởi email với SMTP
  15. Socket Programming

Link Download (PDF & EPUB): https://github.com/voduytuan/python-book-for-dummies

Hy vọng mọi người thấy cuốn sách nhỏ này hữu ích và sẽ không ngại học ngôn ngữ Python vì tương lai Python sẽ là một ngôn ngữ rất hot. Và cũng đừng quên tham gia và đóng góp nhiều hơn cho cộng đồng open source.

Enjoy learning & Coding!

Categories
PHP

PHP build và deploy với Jenkins và Docker

7.jenkins-dashboard
Bạn thường deploy code bằng cách nào? Sử dụng FTP để drag & drop file từ máy lên server? Hôm nay mình sẽ chia sẻ cho mọi người một cách deploy code bài bản hơn một chút nhờ sử dụng Jenkins. Ngoài ra, Bài viết cũng tập trung cho các dự án code bằng PHP và có sử dụng một số đồ chơi để phân tích code PHP khi build. Nối tiếp chuỗi bài viết về Docker, bài viết này cũng sẽ hướng dẫn chạy Jenkins trên môi trường Docker.

Jenkins là gì

Nếu như các bạn có quan tâm đến các kỹ thuật CI/CD thì sẽ không thể không biết đến “anh đại” Jenkins. Jenkins là một bộ phần mềm viết bằng Java và hỗ trợ rất mạnh mẽ việc build và deploy code trong quá trình triển khai code lên các môi trường mà bạn đang làm việc như test, beta, production…

Trước đây, để cài đặt một server Jenkins thì đỏi hỏi khá nhiều công sức và khá rắc rối khiến cho nhiều anh chị em bỏ cuộc nữa chừng, khiến cho việc tiếp cận với các đồ chơi của Jenkins bị hạn chế. Và trước đây mình cũng nhiều lần cài đặt Jenkins và cũng vọc nhưng cũng không thấy mặn mà lắm vì mỗi lần cài đặt, setup khá vất vả.

Tuy nhiên, nhờ sự trợ giúp của Docker, ngày nay, việc cài đặt Jenkins là một trải nghiệm “sung sướng”. Chỉ cần pull image chính thức của Jenkins và làm theo một số chỉ dẫn tại https://hub.docker.com/_/jenkins/ là đã nhanh chóng dựng được Jenkins để trải nghiệm quá trình build và deploy code nhanh chóng.

Jenkins và PHP

Mục tiêu của phần này giới thiệu đến mọi người một Jenkins Docker image mà mình xây dựng riêng cho các dự án hằng ngày là tích hợp sắn các phần mềm và plugin kèm theo trong jenkins cho PHP. Image này mình có public trên docker hub, có tên là “voduytuan/jenkins-php-docker”.

Một số đồ chơi PHP cài thêm cho server này là:
– Toàn bộ đồ chơi tại http://jenkins-php.org (loại trừ phpdox mình không xài nên không cài)
– Xdebug extension để generate code coverage report
– Jenkins Git plugin để pull code từ repo Github hoặc Bitbucket..
– Jenkins Push Over SSH plugin để deploy code lên server
– Docker bên trong jenkins (^^!) để build các image và push lên private registry cho các dự án microservice
Các bạn có thể tham khảo Dockerfile để biết thêm các đồ chơi mình cài cũng như có thể tạo riêng cho mình một image với các đồ chơi theo nhu cầu của bạn.

Bạn có thể start Jenkins bằng câu lệnh sau:
~ > docker run -d --name jenkins -p 9090:8080 -v /data/jenkins/jenkins-php-docker:/var/jenkins_home:rw voduytuan/jenkins-php-docker

Hướng dẫn tham số:
– “-v /data/jenkins/jenkins-php-docker:/var/jenkins_home:rw”: Một tham số cần lưu ý là mount volume thư mục data của jenkins (/var/jenkins_home). Đây là toàn bộ dữ liệu của Jenkins trong quá trình sử dụng. Ở đây mình mount vào thư mục /data/jenkins/jenkins-php-docker trên máy. Bạn có thể để thư mục “jenkins-php-docker” là rỗng hoặc clone từ repo của mình (https://github.com/voduytuan/jenkins-php-docker) để có sẵn một template tên là “php-template” để sau này khi tạo project thì sử dụng template để tạo nhanh các cấu hình build dự án. Lưu ý việc phân quyền user cho thư mục bạn mount volume. Đơn giản nhất là cứ quyền 0777.

Sau khi chạy docker run, chờ một thời gian (một vài phút tùy server) để Jenkins khởi động và bạn có thể truy cập đến Jenkins thông qua IP của server và port bạn khai báo (vd: 9090). Nếu thành công, bạn sẽ thấy màn hình như bên dưới:

0.jenkins-plain
Dashboard của Jenkins

Khởi tạo Jenkins

Khi chạy Jenkins lần đầu thì Jenkins hoàn toàn không có một cơ chế bảo mật nào hết và cho phép truy cập ẩn danh. Bạn có thể làm theo 1 số thao tác đơn giản sau để tạo tài khoản Admin và phân quyền lại cho an toàn hệ thống.

1.jenkins-firststep
Manage Jenkins

Vào Manage Jenkins > Configure Global Security và chỉnh như hình bên dưới để cho phép tạo tài khoản:

2.jenkins-config-global-security
Configure Global Security

Sau khi cấu hình, nhấn lưu thì góc trên bên phải sẽ hiện link đăng ký, và đăng nhập. Tiến hành đăng ký tài khoản đầu tiên.

3.jenkins-create-user
Jenkins create new user

Sau khi tạo tài khoản và đăng nhập vào, bạn quay lại trang “Configure Global Security” để cấu hình như bên dưới.

4.jenkins-config-global-security-matrix-permission
Configure Global Security

(Nội dung thay đổi là bỏ cho phép đăng ký và chọn hình thức Authorization là Matrix-based security và add user bạn vừa tạo vào bảng phân quyền, đồng thời chọn hết các quyền cho user này, sau đó nhấn Apply và Save để hoàn tất quá trình thay đổi.

Ngoài ra, cũng trong trang này, phần “Markup Formatter” chọn là “Raw HTML” để trong trang dự án hiển thị HTML được trong phần “Description”.

Với tài khoản hiện tại, bạn có thể tạo tài khoản cho các thành viên khác có nhu cầu sử dụng hệ thống và phân quyền theo nhu cầu của bạn. Bài viết sẽ không đi sâu vào hướng dẫn phân quyền, bạn có thể tham khảo trên google hoặc trên trang web chính thức của Jenkins.

Sau khi quyền hạn và cài đặt đã xong, bạn tiến hành tạo project để thực hiện CI/CD cho dự án của mình.

Tạo project và tiến hành build

– Tạo một project mới và đặt tên tùy ý và với template mẫu là “php-template” (nếu bạn thư mục mount có project đã clone từ repo của mình hướng dẫn). (Xem hình)

5.jenkins-new-project
Create new project in Jenkins

Nhấn OK để tạo và đến trang cấu hình của dự án này. Trang cấu hình là trang quan trọng nhất của dự án bởi nó sẽ giúp bạn cài đặt các thao tác cho dự án này.

6.jenkins-project-configuration
Project Configuration

Có 3 bước cơ bản (quan trọng) trong trang cấu hình bạn cần biết là:
1. SCM: Bạn cần link đến repo source code của bạn. Mặc định Jenkins ko hỗ trợ Git, nhưng bản Docker image của mình đã cài Git plugin nên bạn có thể cấu hình liên kết đến các Git repo (github, bitbucket…). Ví dụ cấu hình Git:

12.jenkins-scm
Git SCM

2. Build: dùng để cấu hình, chọn các cách thức build dự án. Ở template “php-template” thì mình build bằng Apache Ant (thông qua file build.xml tại thư mục gốc của sourcecode – mình sẽ share file build.xml mẫu cho một dự án php ở cuối bài).

3. Post-build action: là các thao tác được thực hiện. Đó có thể là phân tích các file output (xml, json..) từ bước build tạo ra và tạo các report, hoặc là SSH vào remote server để deploy code, thực hiện một câu lệnh nào đó hoặc build một docker image mới rồi push lên repo sau khi build success. Có rất nhiều plugin của Jenkins hỗ trợ nhiều khía cạnh build khác nhau. Có thể tham khảo thêm trên Jenkins plugin. Hình chụp một số Post-build action trong dự án của mình:

Post build Action vẽ biểu đồ
Post build Action vẽ biểu đồ

Post build action Push Over SSH
Post build action Push Over SSH

Một số kết quả generate từ các post-build action theo template mẫu “php-template”:

8.project-dashboard
Jenkins Project Dashboard

9.jenkins-code-coverage
PHPUnit Code Coverage Report

10.jenkins-plot
Jenkins Plot

10.jenkins-jdepend
JDepend Report

Bạn có thể tìm hiểu thêm tại http://jenkins-php.org/ để hiểu rõ về cách đọc các report về ứng dụng PHP của bạn.

Hy vọng những chia sẻ về Jenkins này sẽ giúp bạn nhanh chóng và dễ dàng triển khai Jenkins cho hệ thống của mình để quá trình build và deploy code được tự động, nhanh chóng và an toàn hơn.


Cấu trúc thư mục của dự án Apitoy để mọi người hiểu hơn về các đường dẫn trong file config.
apitoy-directory
File sample build.xml dùng cho Ant cho dự án của mình, chia sẻ để mọi người tham khảo.

Trong file build.xml có sử dụng 2 file xml khác cho phpmd và phpunit. 2 file này cũng được chia sẻ bên dưới.

Categories
Technology

Triển khai môi trường web bằng Docker

docker introduction

Số là dạo này làm việc và nghiên cứu nhiều về kiến trúc Microservice và đang chuyển toàn bộ kiến trúc sang Microservice. Trong quá trình này, Docker là một công nghệ không thể nào bỏ qua vì Docker sẽ giúp ích rất nhiều trong quá trình triển khai và quản lý các service. Trong phạm vi bài viết này mình sẽ không đi sâu vào chi tiết kiến trúc Microservice cũng như mô tả kỹ về hoạt động của Docker mà sẽ tập trung vào giới thiệu sơ về Docker và dựng một môi trường thực tế dùng Docker để triển khai Web Server cho một website.