كما
سمع الجميع بالفعل ، في نهاية مايو أطلقت Telegram خادم MTProto Proxy الرسمي (المعروف أيضًا باسم MTProxy) ، المكتوب باللغة
التالية . في عام 2018 ، لا يوجد الكثير بدون Docker ، لأنه مصحوب بنفس
الطريقة "الرسمية" بتنسيق صفر التكوين. كل شيء سيكون على ما يرام ، لكن ثلاثة "استثناءات" أفسدت انطباع الإصدار قليلاً: الصورة تزن> 130 ميجا بايت (هناك دبيان ممتلئ الجسم ، وليس جبال الألب المعتادة) ، بسبب "التكوين صفر" لا يتم تكوينه بشكل ملائم دائمًا (فقط من خلال إعدادات البيئة) ونسي الرجال الحملة ، ووضعوا ملف Dockerfile.
TL ؛ DR سنقوم بعمل صورة عامل إرساء رسمي على أساس جبال الألب عمليا 1 في 1 بحجم 5.94 ميجا بايت ووضعها
هنا (وملف Dockerfile
هنا ) ؛ على طول الطريق ، سنكتشف كيف يمكنك في بعض الأحيان تكوين صداقات مع برنامج Alpine باستخدام القصاصات والملف ، وسنلعب قليلاً في الحجم ، حصريًا من أجل المتعة.
محتوى الصورة
مرة أخرى ، بسبب كل هذه الضجة؟ دعونا نرى ما تمثله الصورة الرسمية مع الأمر
history :
$ docker history --no-trunc --format "{{.Size}}\t{{.CreatedBy}}" telegrammessenger/proxy
تتم قراءة الطبقات من الأسفل إلى الأعلى على التوالي:

أثقلها هو Debian Jessie ، الذي ورثت منه الصورة الأصلية ، يجب أن نتخلص منه أولاً (alpine: 3.6 ، للمقارنة ، يزن 3.97 ميغابايت) ؛ متبوعة بأبعاد هي حليقة وشهادات جديدة. لفهم ما يعنيه الملفان الآخران والدليل ، سننظر في الداخل باستخدام الأمر
run ، واستبدال CMD بـ bash (سيسمح لك هذا بالتجول في الصورة التي تم إطلاقها ، والتعرف على بعضكما عن كثب ، وتشغيل أجزاء معينة ، ونسخ شيء مفيد):
$ docker run -it --rm telegrammessenger/proxy /bin/bash
الآن يمكننا بسهولة استعادة صورة الحادث - شيء يشبه ملف Dockerfile الرسمي المفقود:
FROM debian:jessie-20180312 RUN set -eux \ && apt-get update \ && apt-get install -y --no-install-recommends curl ca-certificates \ && rm -rf /var/lib/apt/lists/* COPY ./mtproto-proxy /usr/local/bin RUN mkdir /data COPY ./secret/ /etc/telegram/ COPY ./run.sh /run.sh CMD ["/bin/sh", "-c", "/bin/bash /run.sh"]
عندما يكون mtproto-proxy خادمًا مترجمًا ، يحتوي المجلد السري فقط على ملف hello-explorers-how-you-do-do مع مفتاح التشفير AES (انظر أوامر الخادم ، هناك بالمناسبة ، هناك توصية رسمية للحصول على المفتاح من خلال واجهة برمجة التطبيقات ، ولكن ضعه على هذا النحو ربما لتجنب الموقف عندما يتم حظر واجهة برمجة التطبيقات أيضًا) ، ويقوم run.sh بكل الاستعدادات لبدء الوكيل.
التجمع
تحت CentOS 7 MTProxy على Habré التي
تم جمعها بالفعل ، سنحاول جمع صورة تحت Alpine وحفظ 130 ميغابايت ، الإعلانات التجارية ، 130 في صورة عامل الميناء الناتج.
السمة المميزة لـ Alpine Linux هي استخدام musl بدلاً من glibc. كلاهما مكتبات C القياسية. Musl صغير (ليس لديه خمس "المعيار" فيه) ، لكن الحجم والأداء (الموعود على الأقل) يقرران متى يتعلق الأمر بـ Docker. إن وضع glibc على جبال الألب ليس صحيحًا من الناحية العرقية ،
ولن يفهم العم جاكوب جوتيركا ، على سبيل المثال.
سنقوم أيضًا ببناء عامل ميناء لعزل التبعيات والحصول على حرية التجريب ، لذلك قم بإنشاء ملف Dockerfile جديد:
FROM alpine:3.6 RUN apk add --no-cache git make gcc musl-dev linux-headers openssl-dev RUN git clone --single-branch --depth 1 https://github.com/TelegramMessenger/MTProxy.git /mtproxy/sources RUN cd /mtproxy/sources \ && make -j$(getconf _NPROCESSORS_ONLN)
من التبعيات ، سيكون git في متناول اليد (وليس فقط لاستنساخ المستودع الرسمي ، سيحدد ملف make sha التزامًا بالإصدار) ، وإنشاء ، وملفات gcc ، ورأس (تم الحصول على الحد الأدنى من المجموعة تجريبيًا). نحن نستنسخ الفرع الرئيسي فقط بعمق التزام واحد (بالتأكيد لا نحتاج إلى التاريخ). حسنًا ، دعنا نحاول استخدام جميع موارد المضيف عند الترجمة باستخدام -j. قمت بتقسيمها عمداً إلى عدد أكبر من الطبقات من أجل الحصول على ذاكرة تخزين مؤقت مناسبة أثناء إعادة البناء (عادة ما يكون هناك الكثير منها).
سنقوم بتشغيل أمر
البناء (يجري في الدليل مع ملف Dockerfile):
$ docker build -t mtproxy:test .
وهذه هي المشكلة الأولى:
In file included from ./net/net-connections.h:34:0, from mtproto/mtproto-config.c:44: ./jobs/jobs.h:234:23: error: field 'rand_data' has incomplete type struct drand48_data rand_data; ^~~~~~~~~
في الواقع ، سيتم ربط جميع تلك اللاحقة به. أولاً ، بالنسبة لأولئك الذين ليسوا على دراية بأنفسهم ، فإن المترجم يقسم بالفعل على عدم وجود إعلان عن بنية بيانات drand48_data. ثانياً ، سجل مطورو musl وظائف عشوائية آمنة باستخدام الخيط (مع postr _r) وعلى كل ما يتعلق بها (بما في ذلك الهياكل). كما أن مطوري Telegram ، بدورهم ، لم يكلفوا أنفسهم عناء تجميع الأنظمة التي لم يتم تنفيذ عشوائي_r ونظرائها (في العديد من مكتبات أنظمة التشغيل ، يمكنك رؤية إشارة HAVE_RANDOM_R أو وجودها التعسفي أو غيابها لهذه المجموعة من الوظائف عادة ما يؤخذ في الاعتبار في التكوين التلقائي).
حسنًا ، الآن سنقوم بالتأكيد بتثبيت glibc؟ لا! سنقوم بنسخ ما نحتاجه من glibc إلى الحد الأدنى ونقوم بعمل تصحيح لمصادر MTProxy.
بالإضافة إلى المشاكل المتعلقة بـ random_r ، فإننا نواجه مشكلة في وظيفة backtrace (execinfo.h) ، والتي تُستخدم لإخراج مكدس backtrace في حالة وجود استثناء: يمكنك محاولة استبدالها بالتنفيذ من libunwind ، ولكن الأمر لا يستحق ذلك ، لأنه تم تأطير المكالمة عن طريق التحقق من __GLIBC__.
Random_compat.patch محتويات التصحيح ضعه في مجلد ./patches وقم بتعديل ملف Dockerfile قليلاً لتطبيق التصحيح على الطاير:
FROM alpine:3.6 COPY ./patches /mtproxy/patches RUN apk add --no-cache --virtual .build-deps \ git make gcc musl-dev linux-headers openssl-dev \ && git clone --single-branch --depth 1 https://github.com/TelegramMessenger/MTProxy.git /mtproxy/sources \ && cd /mtproxy/sources \ && patch -p0 -i /mtproxy/patches/randr_compat.patch \ && make -j$(getconf _NPROCESSORS_ONLN) \ && cp /mtproxy/sources/objs/bin/mtproto-proxy /mtproxy/ \ && rm -rf /mtproxy/{sources,patches} \ && apk add --no-cache --virtual .rundeps libcrypto1.0 \ && apk del .build-deps
الآن تم إطلاق ثنائي mtproto-proxy المجمّع على الأقل ، ويمكننا المضي قدمًا.
إزالة
حان الوقت لتحويل run.sh الأصلي إلى docker-entrypoint.sh. في رأيي ، هذا أمر منطقي عندما يدخل "الربط الإلزامي" إلى ENTRYPOINT (يمكن دائمًا تحميله من الخارج) ، وتناسب الحجج الخاصة بتشغيل التطبيق المحمي بالحد الأقصى في CMD (+ متغيرات البيئة كدراسة).
يمكننا تثبيت bash و grep الكامل في صورتنا الألبية (سأشرح لاحقًا) لتجنب الصداع واستخدام الكود الأصلي كما هو ، لكنه سيضخم صورنا المصغرة للعار ، لذلك سننمو حقيقيًا ، والدته ، بونساي.
لنبدأ مع shebang ، استبدل
#!/bin/bash
بـ
#!/bin/sh
. افتراضي الرماد الألبي قادر على هضم كل بنية bash "كما هي" تقريبًا ، لكننا ما زلنا نواجه مشكلة واحدة - لأسباب غير معروفة ، رفض قبول قوس في أحد الشروط ، لذلك سنقوم بتوسيعه عن طريق عكس منطق المقارنة:

نحن الآن في انتظار مواجهة مع grep ، والتي تختلف في تسليم مشغول boxbox قليلاً عن المعتاد (وبالمناسبة ، أبطأ كثيرًا ، ضع في اعتبارك في مشاريعك). أولاً ، إنه لا يفهم التعبير
{,15}
، وسيتعين عليه تحديد
{0,15}
بشكل صريح. ثانيًا ، لا يدعم علامة
-P
(نمط perl) ، ولكنه يهضم التعبير بهدوء عند تمكين الموسع (-E).
في تبعياتنا ، لا يزال هناك تجعيد فقط (ليس هناك جدوى من استبداله بـ wget من busybox) و libcrypto (هذا يكفي ، opensl غير مطلوب على الإطلاق في هذا التجميع).
ظهر
بناء جميل
متعدد المراحل في Docker قبل بضع سنوات ، وهو مثالي ، على سبيل المثال ، لتطبيقات Go أو في المواقف التي يكون فيها التجميع معقدًا ويسهل نقل العناصر من صورة إلى صورة بدلاً من إجراء التنظيف النهائي. سوف نستخدمه لزرع بونساي لدينا ، وهذا سيوفر القليل.
FROM alpine:3.6 # ( ) RUN apk add --no-cache --virtual .build-deps \ # ... , && make -j$(getconf _NPROCESSORS_ONLN) FROM alpine:3.6 # , , WORKDIR /mtproxy COPY --from=0 /mtproxy/sources/objs/bin/mtproto-proxy . # #
يجب أن يكون بونساي بونساي - تخلص من تثبيت libcrypto. عند البناء ، كنا بحاجة إلى ملفات الرأس من حزمة openssl-dev ، والتي ستسحب في التبعيات libcrypto وسيتم توجيه ملفنا التنفيذي نحو استخدام libcrypto.so.1.0.0. ولكن هذا هو التبعية الوحيدة ، بالإضافة إلى ذلك ، يتم تثبيته مسبقًا في Alpine (في الإصدار 3.6 هو libcrypto.so.41 ، 3.7 - libcrypto.so.42 ، إنه في / lib /). لقد وبخوني الآن ، هذه ليست الطريقة الأكثر موثوقية ، لكنها تستحق ذلك وما زلنا نضيف رابطًا رمزيًا إلى الإصدار الحالي (إذا كان لديك طريقة أفضل ، سأقبل بكل سرور العلاقات العامة).
اللمسات النهائية والنتيجة:
مركز عامل الميناءجيثبسأكون ممتنا لأية نصيحة ومساهمات.