برنامجك الأول في OpenResty: Hello World

API7.ai

September 9, 2022

OpenResty (NGINX + Lua)

عندما نبدأ في تعلم لغة تطوير جديدة، توفر لنا البرامج التعليمية حالة بسيطة مثل hello world. لذا دعونا نتجاوز خطوة التثبيت أولاً ونرى كيفية كتابة هذه الحالة في OpenResty:

$ resty -e "ngx.say('hello world')"
hello world

يجب أن يكون هذا أبسط كود لـ hello world قد رأيته على الإطلاق، مشابه لـ Python:

$ python -c 'print("hello world")'
hello world

وراء هذا الكود تظهر فلسفة OpenResty. يجب أن يكون الكود مختصرًا بما يكفي للتخلص من فكرة "من البداية إلى الاستسلام". ستركز هذه المقالة على حالة hello world.

كما ذكرنا في مقالة ما الفرق بين OpenResty و NGINX، فإن OpenResty يعتمد على NGINX. لذا قد يكون لديك سؤال: لماذا لا نرى ظل NGINX هنا؟ لا تقلق، دعنا نضيف سطرًا من الكود لنرى ما الذي يعمل خلف resty:

$ resty -e "ngx.say('hello world'); ngx.sleep(10)" &

لقد أضفنا طريقة ngx.sleep حتى لا يخرج البرنامج بعد طباعة السلسلة hello world. بهذه الطريقة، لدينا الفرصة لمعرفة:

$ ps -ef | grep nginx
root     15944  6380  0 13:59 pts/6    00:00:00 grep --color=auto nginx

وأخيرًا ظهرت عملية NGINX! يبدو أن أمر resty يقوم بشكل أساسي ببدء خدمة NGINX، إذن ما هو resty؟

قد لا يكون OpenResty مثبتًا على جهازك، لذا دعنا نعود إلى خطوات التثبيت التي تجاوزناها في البداية، ونقوم بتثبيت OpenResty قبل المتابعة.

التثبيت

مثل البرمجيات مفتوحة المصدر الأخرى، يمكننا تثبيت OpenResty بطرق مختلفة، مثل استخدام مدير الحزم الخاص بنظام التشغيل، أو التجميع من الكود المصدري، أو استخدام صورة Docker. ومع ذلك، أنصحك أولاً باستخدام مدير حزم مثل yum، apt-get، و brew لتثبيت OpenResty. في هذه المقالة، سأستخدم نظام macOS كمثال:

$ brew tap openresty/brewbrew install openresty

استخدام أنظمة التشغيل الأخرى مشابه. أولاً، أضف عنوان URL لمستودع OpenResty إلى مدير الحزم، ثم استخدم مدير الحزم لتثبيت OpenResty. لمزيد من الخطوات التفصيلية، يمكنك الرجوع إلى الوثائق الرسمية.

ومع ذلك، هناك مشكلتان وراء هذا التثبيت الذي يبدو بسيطًا:

  1. لماذا لا أنصح باستخدام الكود المصدري لتثبيته؟
  2. لماذا لا يمكن تثبيته مباشرة من المستودع الرسمي لنظام التشغيل بل يجب إعداد مستودع آخر أولاً؟

يرجى التفكير في هذين السؤالين أولاً.

هنا أود أن أضيف شيئًا آخر. سأضع العديد من الأسئلة "لماذا" وراء المظاهر في هذه الدورة. أتمنى أن تفكر أثناء تعلم أشياء جديدة. لا يهم ما إذا كانت النتيجة صحيحة أم لا. لسوء الحظ، التفكير المستقل نادر أيضًا في المجال التقني. بسبب الاختلاف في مجال وعمق كل شخص في المجال التقني، سيكون لدى المعلمين آراء شخصية وأخطاء في المعرفة في أي دورة. يمكننا تشكيل نظامنا التقني الخاص من خلال طرح المزيد من الأسئلة "لماذا" في عملية التعلم وفهمها.

يستمتع العديد من المهندسين بالبناء من الأكواد المصدرية، وأنا أيضًا كنت كذلك منذ سنوات عديدة. ومع ذلك، عند استخدام مشروع مفتوح المصدر، كنت دائمًا أتمنى أن أتمكن من configure و make يدويًا من الكود المصدري وتعديل بعض معلمات التجميع. أشعر أن هذه هي أفضل طريقة لتناسب بيئة هذا الجهاز وتعظيم أدائه.

ولكن هذا ليس هو الحال في الواقع. في كل مرة أقوم بتجميع الكود المصدري، أواجه مشاكل بيئية غريبة، ولا يمكنني تثبيته إلا بعد التعثر. الآن أفهم أن هدفنا الأصلي هو استخدام المشاريع مفتوحة المصدر لحل احتياجات الأعمال. لا ينبغي أن نهدر الوقت والبيئة في القتال، ناهيك عن مديري الحزم وتكنولوجيا الحاويات. إنها بالضبط لمساعدتنا في حل هذه المشاكل.

لنعد إلى الموضوع. استخدام الكود المصدري لـ OpenResty للتثبيت ليس فقط خطوات معقدة، بل تحتاج إلى حل التبعيات الخارجية مثل PCRE، OpenSSL، وما إلى ذلك، ولكنك تحتاج أيضًا إلى ترقيع الإصدار المقابل من OpenSSL يدويًا. وإلا، سيكون هناك نقص في الوظائف عند التعامل مع جلسات SSL. على سبيل المثال، واجهات برمجة تطبيقات Lua مثل ngx.sleep التي تسبب yield لا يمكن استخدامها. إذا كنت تريد معرفة المزيد عن هذا الجزء، يمكنك الرجوع إلى الوثائق الرسمية لمزيد من المعلومات التفصيلية.

يقوم OpenResty بالحفاظ على هذه الترقيعات في نص حزمة OpenSSL بنفسه. عندما يقوم OpenResty بترقية إصدار OpenSSL، يجب عليه إعادة إنشاء الترقيع المقابل وإجراء اختبارات رجوع كاملة.

Source0: https://www.openssl.org/source/openssl-%{version}.tar.gz

Patch0: https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-1.1.0d-sess_set_get_cb_yield.patch
Patch1: https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-1.1.0j-parallel_build_fix.patch

في الوقت نفسه، يمكننا إلقاء نظرة على نص الحزمة لـ OpenResty في CentOS لمعرفة ما إذا كانت هناك نقاط خفية أخرى:

BuildRequires: perl-File-Temp
BuildRequires: gcc, make, perl, systemtap-sdt-devel
BuildRequires: openresty-zlib-devel >= 1.2.11-3
BuildRequires: openresty-openssl-devel >= 1.1.0h-1
BuildRequires: openresty-pcre-devel >= 8.42-1
Requires: openresty-zlib >= 1.2.11-3
Requires: openresty-openssl >= 1.1.0h-1
Requires: openresty-pcre >= 8.42-1

كما ترى هنا، يحافظ OpenResty على إصداره الخاص من OpenSSL وإصداره الخاص من zlib و PCRE. ومع ذلك، قام الأخيران بتعديل معلمات التجميع ولم يحتفظا بترقيعاتهما.

لذلك، مع مراعاة هذه العوامل، لا أنصح بتجميع OpenResty من الأكواد المصدرية إلا إذا كنت تعرف التفاصيل بالفعل.

يجب أن يكون واضحًا لك الآن لماذا لا أنصح بالتثبيت من الكود المصدري. عندما أجبنا على السؤال الأول، أجبنا أيضًا على السؤال الثاني: لماذا لا يمكن التثبيت مباشرة من مستودعات الحزم الرسمية لنظام التشغيل بل يجب إعداد مستودع آخر أولاً؟

هذا لأن المستودعات الرسمية لا ترغب في قبول حزم OpenSSL، PCRE، و zlib التي يحتفظ بها أطراف ثالثة لمنعها من التسبب في ارتباك للمستخدمين الآخرين الذين لا يعرفون أي واحد يختارون. من ناحية أخرى، يحتاج OpenResty إلى إصدارات محددة من مكتبات OpenSSL و PCRE ليعمل بشكل طبيعي، والإصدارات الافتراضية للنظام قديمة نسبيًا.

واجهة سطر أوامر OpenResty

بعد تثبيت OpenResty، يتم تثبيت واجهة سطر أوامر OpenResty resty بشكل افتراضي. إنها نص Perl، وكما ذكرنا سابقًا، فإن أدوات نظام OpenResty مكتوبة جميعها بـ Perl، وهو ما يحدده تفضيل المؤلف التقني لـ OpenResty.

$ which resty
/usr/local/bin/resty

$ head -n 1 /usr/local/bin/resty
#!/usr/bin/env perl

واجهة سطر أوامر resty قوية جدًا، ويمكننا استخدام resty -h أو قراءة الوثائق الرسمية للحصول على قائمة كاملة بالوظائف. بعد ذلك، سأقدم ميزتين مثيرتين للاهتمام.

$ resty --shdict='dogs 1m' -e 'local dict = ngx.shared.dogs dict:set("Tom", 56) print(dict:get("Tom"))'

56

يوضح المثال أعلاه تكوين Nginx مع كود Lua، والذي يقوم بإعداد واستعلام قاموس ذاكرة مشتركة. dogs 1m هو تكوين Nginx يعلن عن مساحة ذاكرة مشتركة باسم dogs بحجم 1m. يتم استخدام الذاكرة المشتركة كقاموس في كود Lua.

أيضًا، يتم استخدام المعلمات --http-include و --main-include لإعداد ملف تكوين NGINX، لذا يمكننا إعادة كتابة المثال أعلاه على النحو التالي:

$ resty --http-conf 'lua_shared_dict dogs 1m;' -e 'local dict = ngx.shared.dogs dict:set("Tom", 56) print(dict:get("Tom"))'

أدوات التصحيح القياسية في عالم OpenResty، مثل gdb، valgrind، sysetmtap، و Mozilla rr يمكن أيضًا استخدامها مع resty لتسهيل التطوير والاختبار العاديين. لديهم أوامر مقابلة لـ resty، لذا فإن التطبيق الداخلي بسيط، مجرد طبقة إضافية من استدعاءات سطر الأوامر. لنأخذ valgrind كمثال.

$ resty --valgrind -e "ngx.say('hello world'); "

ERROR: failed to run command "valgrind /usr/local/openresty/nginx/sbin/nginx -p /tmp/resty_rJeOWaYGIY/ -c conf/nginx.conf": No such file or directory

إنها ليست فقط قابلة للتطبيق في عالم OpenResty، بل هي أيضًا أدوات عامة للجانب الخادم، لذا دعونا نتعلمها خطوة بخطوة.

"hello world" أكثر رسمية

أول برنامج OpenResty كتبناه في البداية استخدم أمر resty بدون عملية master وبدون الاستماع على منافذ محددة. بعد ذلك، دعونا ننفذ برنامج hello world آخر.

نحتاج إلى ثلاث خطوات على الأقل لإكماله.

  1. إنشاء دليل عمل.
  2. تعديل ملف تكوين NGINX لتضمين كود Lua فيه.
  3. بدء خدمة OpenResty.

لنبدأ بإنشاء دليل عمل.

$ mkdir openresty-sample
$ cd openresty-sample
$ mkdir logs/ conf/

فيما يلي تكوين nginx.conf بسيط مع توجيه content_by_lua الخاص بـ OpenResty في الدليل الجذر، والذي يضمّن طريقة ngx.say.

events {
    worker_connections 1024;
}

http {
    server {
        listen 8080;
        location / {
            content_by_lua '
                ngx.say("hello, world")
            ';
        }
    }
}

يرجى التأكد من إضافة openresty إلى متغير البيئة PATH أولاً؛ ثم بدء خدمة OpenResty:

$ openresty -p `pwd` -c conf/nginx.conf

إذا لم تحدث أية أخطاء، فقد تم بدء خدمة OpenResty بنجاح. يمكننا الوصول إليها باستخدام أمر cURL لرؤية النتائج المرتجعة.

$ curl -i 127.0.0.1:8080

HTTP/1.1 200 OK
Server: openresty/1.13.6.2
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
hello, world

تهانينا! لقد اكتمل برنامج Hello World الرسمي في OpenResty!

الخلاصة

دعونا نراجع ما تعلمناه اليوم. أولاً، نبدأ بتثبيت OpenResty وواجهة سطر الأوامر بسطر بسيط من كود "hello, world"، وأخيرًا نبدأ عملية OpenResty ونشغل برنامج خلفي فعلي.

من بينها، resty هو أداة سطر أوامر سنستخدمها بشكل متكرر في المستقبل. لذلك، يتم تشغيل كود العرض التوضيحي في الدورة باستخدامه، بدلاً من بدء خدمة OpenResty في الخلفية.

الأهم من ذلك، أن هناك العديد من التفاصيل الثقافية والتقنية المخفية وراء OpenResty، وهي تشبه جبل جليد يطفو على البحر. من خلال هذه الدورة، أتمنى أن أريكم OpenResty بشكل أكثر شمولاً، وليس فقط واجهات برمجة التطبيقات الظاهرة.