ساخت پروژه با معماری مایکروسرویس، زبان گولنگ، اندپوینت رست، کوبرنتیز و... (قسمت اول)

داستان از اونجایی شروع شد که دنبال شغل تو کشورای دیگه گشتم، به عنوان گولنگ دولوپر اقدام کردم، تقریبا هر شرکتی که به گولنگ کار میکرد مایکروسرویس هم کار میکرد پس یه گوگل کردم و به این مطلب توی مدیوم رسیدم، دیدم جالبه گفتم ترجمه کنم تا بهتر تو ذهنم بمونه، این آموزش قرار نیست توضیح بده مایکروسرویس چیه یا چطور کار میکنه و کجا به درد شما میخوره، این مطلب فقط توضیح میده چطور پیاده سازی کنیم. خیلی خب توضیح بسته بریم سراغ متن اصلی نویسنده.




تو اینترنت کلی مطلب درباره ساخت سرویس رست‌فول با معماری مایکروسرویس توسط زبان گولنگ وجود داره، دنبال بهترین شیوه برای شرکتم بودم و بیشتر این مطالب رو خوندم، بالاخره بهترین شیوه برای پیاده سازی معماری مایکروسرویس پیدا کردم، این شیوه توسط فریمورک protobuf/gRPC که گوگل توسعه میده پیاده سازی میشه، مطمئنم همه درباره‌ش خوندید یا بعضی‌ها همین الآن دارید از این شیوه استفاده می‌کنید، ولی فکر میکنم کمتر کسی تجربه توسعه رست‌فول با معماری مایکروسرویس توسط فریمورک protobuf/gRPC داشته باشه، من فقط یه مطلب تو مدیوم در این باره پیدا کردم:

https://medium.com/@thatcher/why-choose-between-grpc-and-rest-bc0d351f2f84

من نمیخوام دوباره این مطلب رو توضیح بدم، میخوام قدم به قدم توضیح بدم چطور یک اپلیکیشن "To Do list" با معماری مایکروسرویس، gRPC و اندپوینت‌های رست توسعه بدید. می‌خوام نشون بدم چطور تو معماری مایکروسرویس تست و میدلور (request-ID and logging/tracing) بنویسید. همچنین با مثال توضیح میدم چطور این اپلیکیشن را بیلد بگیرید و در انتها روی کوبرنتیز دپلوی کنید.

این آموزش ۴ قسمت خواهد داشت:

  • قسمت یک: چطور یک سرویس‌دهنده و سرویس‌گیرنده gRPC بنویسیم.
  • قسمت دو: چطور اندپوینت‌های رست رو به سرویس gRPC اضافه کنیم.
  • قسمت سه: چطور میدلور (logging/tracing) به سرویس gRPC و رست اضافه کنیم.
  • قسمت چهار: چطور کوبرنتیز رو کانفیگ کنید و health check اضافه کنیم. (احتمالا این قسمت رو ترجمه نمیکنم میتونید از وبلاگ اصلی بخونید)

پیش‌نیازها:

  • این آموزش زبان گولنگ نیست، شما باید از قبل کد زدن با گولنگ رو بلد باشید.
  • باید گولنگ ورژن ۱.۱۱ یا بالاتر رو نصب کنید، ما می‌خوایم از قابلیت ماژول گولنگ استفاده کنیم که از این ورژن در دسترسه.
  • شما باید نصب و راه‌اندازی MySQL بلد باشید، ما برای ذخیره اطلاعات از این دیتابیس استفاده می‌کنیم.

ا- API first

این یعنی چی؟ (این قسمت سادس و ترجمه‌ش واقعا بی‌معنی میشد)

  • API definition MUST be language-, protocol-, transport- neutral
  • API definition and API implementation MUST be loosely coupled
  • API versioning
  • I need to exclude manual work to sync API definition, API implementation and API documentation. I need API implementation stubs/skeleton and API documentation are generated from API definition automatically.

در طول آموزش این نکات رو بیشتر باز میکنم.


اپلیکیشن ToDo list با معماری مایکروسرویس

این اپلیکیشن باید تسک‌هارو مدیریت کنه، پس جدولمون باید این فیلدهارو داشته باشه:

  • ID (unique integer identifier)
  • Title (text)
  • Description (text)
  • Reminder (timestamp)

اپلیکیشن todo به طور معمول شامل اندپوینت‌های ایجاد، دریافت، اصلاح، حذف و همچین دریافت همه تسک‌ها می‌شود.


قسمت اول: ایجاد سرویس gRPC CRUD

قدم اول: تعریف API توسط proto

قسمت یک درباره چگونگی ساخت توسعه سرویس‌دهنده gRPC CRUD و سرویس‌‌گیرنده‌ش برای تست است.

سورس کد قسمت یک از اینجا در دسترس‌تونه
https://github.com/amsokol/go-grpc-http-rest-microservice-tutorial/tree/part1

قبل اینکه شروع کنیم نیاز داریم تا ساختار پروژه رو تعریف کنیم.

این یه الگوی خوب برای پروژه‌های گولنگه:

https://github.com/golang-standards/project-layout

لطفا این رو همونطوری که من استفاده کردم استفاده کنید.

من از ویندوز ۱۰ ۶۴ بیت استفاده کردم، با این اوصاف فکر نمیکنم مشکلی برای تبدیل این دستورات برای مک یا لینوکس داشته باشید.

در مرحله اول یک پوشه درجایی از کامپیوتر (برای اینکه بتونیم از گو ماژول استفاده کنیم باید خارج از GOPATH پوشه رو بسازیم) برای ایجاد پروژه بسازید. حالا پروژه رو مقدار دهی اولیه میکنیم:

mkdir go-grpc-http-rest-microservice-tutorial

cd go-grpc-http-rest-microservice-tutorial

go mod init github.com/<you>/go-grpc-http-rest-microservice-tutorial

حالا پوشه‌ای برای تعریف API ها میسازیم:

mkdir -p api\proto\v1

پوشه v1 برای ورژن یک API ساخته شده.

درباره API ورژنینگ: این شیوه من برای ساخت ورژن‌های مختلف از API است، هر ورژن داخل فولدری با اسم خودش ساخته میشه.

مرحله بعد ساخت فایل todo-service.proto داخل پوشه api\proto\v1 و اضافه کردن متد ایجادِ ToDoService برای شروع.

https://gist.github.com/amsokol/bce8ddf48b834bd1d4689dc8b9ceb45c

شما میتونید از لینک زیر بیشتر درمورد proto بخونید:

https://developers.google.com/protocol-buffers/docs/proto3
  • حالا Proto compiler binaries از اینجا دانلود کنید:
https://github.com/protocolbuffers/protobuf/releases
  • محتوای پوشه bin رو خارج کنید و آدرسش رو به path های environment variable سیستمون اضافه کنید.
  • پوشه “third_party” داخل روت اصلی پروژه بسازید
  • محتوای پوشه “include” داخل پوشه “third_party” کپی کنید.
ساختار پروژه باید شبیه این باشد
ساختار پروژه باید شبیه این باشد
  • حالا کد جنریتور Proto نصب کنید
go get -u github.com/golang/protobuf/protoc-gen-go
  • فایل protoc-gen.cmd داخل پوشه “third_party” بسازید. برای مک و لینوکس فایل protoc-gen.sh بسازید و محتوای زیر رو در آن کپی کنید:
protoc --proto_path=api/proto/v1 --proto_path=third_party --go_out=plugins=grpc:pkg/api/v1 todo-service.proto
  • فولدری برای خروجی کدهای ساخته شده توسط کد ایجاد میکنیم:
mkdir -p pkg/api/v1
  • مطمئن بشید تو پوشه go-grpc-http-rest-microservice-tutorial هستید و دستور زیر را اجرا کنید:
// for windows
.\third_party\protoc-gen.cmd

// for mac/linux
./third_party/protoc-gen.sh

این دستور فایل todo-service.pb.go داخل فولدر “pkg/model/v1” میسازه.

در نتیجه خروجی باید چیزی شبیه این باشه
در نتیجه خروجی باید چیزی شبیه این باشه

نتیجه جالب بود. حالا بیاید بقیه متدهای todo service اضافه کنیم و کامپایلش کنیم

https://gist.github.com/amsokol/9a4cdd4d53f7f32757cc06d34d2c6097

و دوباره کامپایلر پروتو اجرا کنیم تا کدها آپدیت بشه:

// for windows 
.\third_party\protoc-gen.cmd 

// for mac/linux 
./third_party/protoc-gen.sh
این فایل ها باید داخل CI/CD ساخته بشه و به صورت دستی اجراش نکنید.

تموم شد! API ها رو تعریف کردیم.

قدم دوم: توسعه API توسط گولنگ

من از MySQL استفاده میکنم، شما میتونید هر دیتابیسی که باهاش راحت ترید انتخاب کنید.

با استفاده از کوئری پایین جدول ToDo می‌سازیم:

https://gist.github.com/amsokol/245f734d10a410bf2701e4c9482c9ceb
تو این پست توضیح ندادم چطور MySQL نصب کنید یا چطور دیتابیس توش ایجاد کنید و کوئری بزنید، انتظار دارم اینارو بلد باشید یا تو اینترنت سرچ کنید.

فایل “pkg/service/v1/todo-service.go” با محتوای زیر ایجاد می‌کنید:

https://gist.github.com/amsokol/bb7987f6247bdca80eec65ecf21a9b31
ساختار پروژه باید شبیه به این شده باشه
ساختار پروژه باید شبیه به این شده باشه

و تمام.

قدم سوم: نوشتن تست برای API

مهم نیست داریم چی رو توسعه میدیم، باید تست بنویسیم، این یه قانونه.

این یه لایبرری خوب برای ماک کردن دیتابیس‌های SQL هستش.

https://github.com/DATA-DOG/go-sqlmock

از این برای نوشتن تست سرویس تودولیست استفاده میکنم.

این فایل رو در فولدر “pkg/service/v1” ذخیره کنید، پروژه تون باید شبیه عکس پایین شده باشه:

تمام.

قدم چهارم: ایجاد سرور gRPC

فایل “pkg/protocol/grpc/server.go” همراه با محتوایات پایین بسازید:

https://gist.github.com/amsokol/e52d2c3e601b128e9d02a2a5f1ad1fd5

فانکشن RunServer یک سرویس ToDo میسازه و سرور gRPC اجرا میکنه.

در واقعیت شما باید TLS برای gRPC کانفیگ کنید، اینجا میتونید با یک مثال ببینید چطور باید این کارو انجام بدید.

حالا فایل “pkg/cmd/server.go” همراه با محتوای پایین ایجاد کنید:

https://gist.github.com/amsokol/46d5f4794c8d3b8122d93352ac074969

این فانکشن RunServer پارامترهای کامندلاین موقع اجرای برنامه دریافت میکنه، با سرور MySQL ارتباط برقرار میکنه، یک سرویس ToDo ایجاد میکنه و فانکشن RunServer قبلی رو از سرور gRPC اجرا میکنه.

در آخر فایل “cmd/server/main.go” با محتوای زیر بسازید:

https://gist.github.com/amsokol/7f27b64aeaa4a81541eb9c00f77f3f90

این تمام چیزی بود که سمت سرور اتفاق میفته، در آخر پروژه باید به این شکل باشه:

قدم پنجم: ساخت کلاینت gRPC

فایل “cmd/client-grpc/main.go” همراه با محتوای زیر بسازید:

https://gist.github.com/amsokol/fa4c6046b8bc7d3dcc19329355e60173

این تمام اتفاقیه که سمت کلاینت میفته، خروجی پروژه‌تون باید شبیه عکس پایین باشه.

قدم ششم: اجرای سرور و کلاینت gRPC

این قدم آخره تا اطمینان پیدا کنیم سرور gRPC درست کار میکنه.

با استفاده از ترمینال سرور gRPC بیلد میگیریم و اجرا می‌کنیم (پارامترهای دیتابیس رو باتوجه به کانفیگ خودتون تغییر بدید)

cd cmd/server
go build .
server.exe -grpc-port=9090 -db-host=<HOST>:3306 -db-user=<USER> -db-password=<PASSWORD> -db-schema=<SCHEMA>

اگر همچین خروجی مشاهده کردید:

2018/10/13 12:17:23 starting gRPC server...

این یعنی سرور اجرا شده.

حالا یه ترمینال دیگه باز میکنیم و کلاینت رو بیلد میگیریم و اجرا میکنیم

cd cmd/client-grpc
go build .
client-grpc.exe -server=localhost:9090

اگر خروجی شبیه این بود:

2018/10/13 12:22:18 Create result: <api:"v1" id:2 >
2018/10/13 12:22:18 Read result: <api:"v1" toDo:<id:2 title:"title (2018-10-13T08:52:18.373811Z)" description:"description (2018-10-13T08:52:18.373811Z)" reminder:<seconds:1539420738 > > >
2018/10/13 12:22:18 Update result: <api:"v1" updated:1 >
2018/10/13 12:22:18 ReadAll result: <api:"v1" toDos:<id:2 title:"title (2018-10-13T08:52:18.373811Z)" description:"description (2018-10-13T08:52:18.373811Z) + updated" reminder:<seconds:1539420738 > > >
2018/10/13 12:22:18 Delete result: <api:"v1" deleted:1 >

یعنی همه چی به خوبی کار میکنه.


خلاصه قسمت اول

تمام این قسمت اول بود، ما سرویس دهنده و سرویس گیرنده gRPC توسعه دادیم.

سورس کد قسمت اول از اینجا در دسترس‌تونه.

قسمت دوم اختصاص پیدا میکنه به چگونگی اضافه کردن اندپوینت‌های رست به سرویس gRPC که امروز توسعه دادیم.