Bài viết này được dịch từ bài viết “Running Go API with Hot Reloading and Docker” của tác giả Zach Johnson. Bài viết giải thích khá chi tiết về mã nguồn, tuy nhiên chưa đưa ra được kết quả demo nên tôi xin bổ sung thêm một số hình ảnh và chú thích giúp các bạn dễ hiểu.

 

 

 

Đây là tutorial hướng dẫn nhanh cách thiết lập môi trường phát triển cục bộ cho một Go API chạy bên trong Docker container với cơ chế Hot Reloading. Giải thích ngắn gọn cho các bạn chưa biết về Hot Reloading. Hot Reloading là một cơ chế cho phép tự động cập nhật các phiên bản mới của mã nguồn mà bạn đã chỉnh sửa trong thời gian runtime. Bằng cách này, ứng dụng của bạn vẫn chạy, đồng thời bạn sẽ không bị mất các trạng thái của ứng dụng. Đây là một thuật ngữ khá quen thuộc với các bạn lập trình React Native. Quay lại chủ đề chính, theo tôi, áp dụng Hot Reloading sẽ giúp việc lập trình ở local trở nên hiệu quả hơn. Source trong bài các bạn có thể tải tại đây 

 

API

Trước hết, chúng sẽ xây dựng một API giả định có đường dẫn cmd/api/main.go Đây là API đơn giản có nhiệm vụ lắng nghe request ở cổng 5000 và trả về câu chào “Hello from the api!”

main.go

Dockerfile

 

Tiếp theo chúng ta cần tạo một Dockerfile định nghĩa cách thức khởi tạo container chứa Go API ở trên.

 

docker file

 

  • Đầu tiên chúng ta thiết lập image cơ sở cho Dockerfile là Go 1.10

  • WORKDIR đặt thư mục làm việc hiện tại trong container là đường dẫn đến repository của ví dụ này.

  • Sau đó thực thi câu lệnh COPY sao chép toàn bộ file trong thư mục ngữ cảnh hiện tại vào container. Chúng ta sẽ sử dụng file Docker-compose để định nghĩa thư mục ngữ cảnh hoặc theo mặc định, thư mục ngữ cảnh là thư mục chúng ta chạy lệnh docker-compose.

  • Tôi sẽ sử dụng hot reloader là CompileDaemon. Có rất nhiều các hot reloader cho ứng dụng Go, song tôi chọn CompileDaemon bởi sự đơn giản và khả năng tương tác cao của nó với Docker.

  • ENTRYPOINT định nghĩa câu lệnh sẽ được chạy khi container khởi động. Trong ví dụ này, chúng ta sẽ chạy lệnh CompileDaemon theo mặc định (câu lệnh này còn có nhiều cờ tùy chọn). Tôi chỉ cần xác định câu lệnh go build sẽ thực hiện build tại thư mục nào và sau đó chạy file binary nào để khởi động server. CompileDaemon sẽ xử lý phần còn lại. Bất cứ khi nào có sự thay đổi đối với file .go, nó sẽ dừng server và tiến hành chạy lại các bước khởi tạo. Các loại file mà nó theo dõi có thể được chỉnh sửa khi cần thiết với cờ -pattern. Thật vi diệu.

 

Docker-compose

 

Một file docker-compose có thể đơn giản hóa sự phối hợp giữa các Docker container. Ví dụ này không thể cho các bạn thấy rõ điều đó, bởi chúng ta sẽ chỉ chạy một service duy nhất. Tuy nhiên trong trường hợp chạy nhiều microservices với một cơ sở dữ liệu cục bộ, các bạn sẽ thấy nó sẽ thật tiện ích.

 

docker compose

 

Trước hết, chúng ta định nghĩa image sẽ được sử dụng chính là API:latest được build từ Dockerfile. Ở host chúng ta sử dụng cổng 5000 và ánh xạ nó tới cổng 5000 trên Docker container. Như vậy, chúng ta có thể tiếp cận API từ bên ngoài Docker container. Dòng cuối cùng định nghĩa một volume mount, đảm bảo cho cơ chế hot reloading có thể hoạt động bên trong Docker container. Nó sẽ liên kết thư mục làm việc hiện tại của chúng ta với thư mục bên trong Docker container, vì vậy mọi sự thay đổi trên file ở máy cục bộ cũng sẽ xảy ra ở bên trong Docker container. Bởi CompileDaemon đang chạy bên trong Docker container, do vậy khi nhận ra một sự thay đổi bên trong file ở container, nó sẽ re-build và re-run lại server.

 

Makefile

Cuối cùng chúng ta tạo một Makefile để đơn giản hóa việc khởi động cũng như tắt một server.

 

make file

Lệnh default dùng để build Dockerfile cho API. Lệnh up khởi động API và chạy nó ở chế độ ngầm. logs giúp chúng ta có thể theo dõi các log trên Docker container. Dưới đây là kết quả màn hình console sau khi tôi chạy lệnh make up và make logs.

 

make up + log

 

 

Vậy là các bạn thấy API đã được khởi động và đang lắng nghe ở cổng 5000. Chúng ta sẽ truy cập vào địa chỉ localhost:5000 để xem điều gì xảy ra nhé. Hola! Hello from the api!

 

result

 

 

Tôi thử thay đổi nội dung câu chào trong file main.go thành “Hello from the api! Welcome to the go docker hot reload example”. Các bạn theo dõi logs sẽ thấy rõ cơ chế hoạt động của hot reloading. Nó tự động “Hard stopping the current process...” sau đó tiến hành re-build và re-run.

 

change

 

 

Còn đây là kết quả khi chúng ta refresh lại trang web. Như các bạn thấy API của chúng ta vẫn chạy và tự động cập nhật lại câu chào theo nội dung tôi đã thay đổi trong file main.go. Hot reloading thật tuyệt vời.

 

result after changing

 

 

Lệnh down thực hiện tắt server. Lệnh test cho phép chạy bất kì thử nghiệm nào trong cây thư mục hiện tại. Lệnh clean thực hiện tắt API và xóa image Docker đã lưu khỏi máy tính của bạn. Điều này rất hữu ích khi bạn chạy một image khác như MYSQL, nó chỉ ghi thông tin vào máy local của bạn mà không có cơ chế làm sạch khi container đã tắt. Các bạn hãy tự thử để trải nghiệm các câu lệnh còn lại.

 

Ý tưởng vận dụng

 

 

Tôi thấy việc vận dụng cơ chế Hot Reloading là một cách hiệu quả để phát triển tại local khi nhiều API đang chạy cùng tương tác với một database. Nó có thể là một cách đơn giản để chạy kiểm thử tích hợp: bằng cách đưa hệ thống chạy cục bộ bên trong các container, bạn có thể thực thi câu lệnh make test để thực hiện tất cả các bài kiểm tra tích hợp cục bộ. Sau dó, bất kỳ sự đổi mã nguồn nào của bạn đều được hot reload mà các Docker image không cần phải re-build. Điều này nhanh hơn nhiều so với việc có một bộ kiểm thử riêng biệt để build và run lại tất cả cơ sở hạ tầng của bạn mỗi lần bạn muốn thay đổi thứ gì đó.