Seperti yang sudah
didengar semua orang, pada akhir Mei Telegram meluncurkan server MTProto Proxy (alias MTProxy) resmi, yang ditulis dalam
bahasa berikut . Pada tahun 2018, tidak ada banyak tempat tanpa Docker, karena disertai dengan cara "resmi" yang sama dalam format zero-config. Semuanya akan baik-baik saja, tetapi tiga "tapi" merusak kesan rilis: gambar berbobot> 130 Mb (ada Debian yang gemuk, bukan Alpine yang biasa), karena "zero-config" tidak selalu mudah dikonfigurasikan (hanya oleh pengaturan lingkungan) dan orang-orang lupa kampanye, lay out Dockerfile.
TL; DR Kami akan membuat gambar docker resmi berbasis alpine 1-in-1 praktis berukuran 5.94MB dan meletakkannya di
sini (dan Dockerfile di
sini ); sepanjang jalan, kami akan mencari tahu bagaimana kadang-kadang Anda dapat berteman dengan perangkat lunak Alpine menggunakan jepit dan file, dan kami akan bermain sedikit dalam ukuran, khusus untuk bersenang-senang.
Konten Gambar
Sekali lagi, karena apa yang diributkan? Mari kita lihat apa yang diwakili gambar resmi dengan perintah
sejarah :
$ docker history --no-trunc --format "{{.Size}}\t{{.CreatedBy}}" telegrammessenger/proxy
Lapisan dibaca dari bawah ke atas, masing-masing:

Yang paling tebal adalah Debian Jessie, dari mana gambar asli diwarisi, kita harus menyingkirkannya terlebih dahulu (alpine: 3.6, sebagai perbandingan, beratnya 3,97MB); diikuti oleh dimensi adalah ikal dan sertifikat segar. Untuk memahami apa arti dua file dan direktori lainnya, kita akan melihat ke dalam menggunakan perintah
run , mengganti CMD dengan bash (ini akan memungkinkan Anda berjalan di sekitar gambar yang diluncurkan, mengenal satu sama lain lebih dekat, menjalankan fragmen tertentu, menyalin sesuatu yang bermanfaat):
$ docker run -it --rm telegrammessenger/proxy /bin/bash
Sekarang kita dapat dengan mudah mengembalikan gambar kejadian - sesuatu seperti Dockerfile resmi yang hilang terlihat seperti:
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"]
Di mana mtproto-proxy adalah server yang dikompilasi, folder rahasia hanya berisi file hello-explorers-how-are-you-do dengan kunci enkripsi AES (lihat perintah server, di sana, merupakan rekomendasi resmi untuk mendapatkan kunci melalui API, tetapi dengan kata lain mungkin untuk menghindari situasi ketika API juga diblokir), dan run.sh melakukan semua persiapan untuk memulai proxy.
Majelis
Di bawah CentOS 7 MTProxy pada Habré yang sudah
dikumpulkan , kami akan mencoba untuk mengumpulkan gambar di bawah Alpine dan untuk menyimpan megabyte, iklan, 130 di gambar buruh pelabuhan yang dihasilkan.
Fitur khas Alpine Linux adalah penggunaan musl, bukan glibc. Keduanya adalah pustaka C standar. Musl kecil (tidak memiliki seperlima dari "standar" di dalamnya), tetapi volume dan kinerja (setidaknya dijanjikan) memutuskan ketika datang ke Docker. Dan menempatkan glibc di Alpine tidak benar secara rasial, paman Jakub Jirutka
tidak akan mengerti , misalnya.
Kami juga akan membangun buruh pelabuhan untuk mengisolasi dependensi dan mendapatkan kebebasan untuk eksperimen, jadi buatlah Dockerfile baru:
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)
Dari dependensi, git akan berguna (dan tidak hanya untuk kloning repositori resmi, file make akan melampirkan sha commit ke versi), make, gcc dan file header (set minimum diperoleh secara empiris). Kami hanya mengkloning cabang master dengan kedalaman 1 komit (kami jelas tidak membutuhkan sejarah). Baiklah, mari kita coba memanfaatkan semua sumber daya host saat kompilasi dengan -j switch. Saya sengaja memecahnya menjadi lebih banyak lapisan untuk mendapatkan caching yang nyaman selama pembangunan kembali (biasanya ada banyak dari mereka).
Kami akan menjalankan perintah
build (berada di direktori dengan Dockerfile):
$ docker build -t mtproxy:test .
Dan inilah masalah pertama:
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; ^~~~~~~~~
Sebenarnya, semua yang berikutnya akan terhubung dengannya. Pertama, bagi mereka yang tidak terbiasa dengan diri mereka sendiri, kompiler sebenarnya bersumpah pada kurangnya deklarasi struktur drand48_data. Kedua, pengembang musl mencetak skor pada fungsi acak thread-safe (dengan postfix _r) dan pada semua yang terhubung dengannya (termasuk struktur). Dan pengembang Telegram, pada gilirannya, tidak repot-repot dengan kompilasi untuk sistem di mana random_r dan rekan-rekannya tidak diimplementasikan (di banyak pustaka OS Anda dapat melihat bendera HAVE_RANDOM_R atau kehadiran + tidak adanya yang sewenang-wenang atau tidak adanya kelompok fungsi ini biasanya diperhitungkan dalam konfigurasi otomatis).
Nah, sekarang kita pasti akan menginstal glibc? Tidak! Kami akan menyalin apa yang kami butuhkan dari glibc ke minimum dan membuat tambalan untuk sumber MTProxy.
Selain masalah dengan random_r, kami mengambil masalah dengan fungsi backtrace (execinfo.h), yang digunakan untuk menampilkan stack backtrace dalam kasus pengecualian: Anda dapat mencoba menggantinya dengan implementasi dari libunwind, tetapi tidak sepadan, karena panggilan dibingkai dengan memeriksa untuk __GLIBC__.
Konten tambalan Random_compat.patch Masukkan ke dalam folder ./patches dan modifikasi Dockerfile kita sedikit untuk menerapkan patch dengan cepat:
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
Sekarang biner mtproto-proxy yang dirakit setidaknya diluncurkan, dan kita bisa melanjutkan.
Izin
Saatnya untuk mengubah run.sh asli menjadi docker-entrypoint.sh. Menurut pendapat saya, ini logis ketika "pengikatan wajib" masuk ke ENTRYPOINT (selalu dapat kelebihan beban dari luar), dan argumen untuk meluncurkan aplikasi buruh pelabuhan sesuai dengan maksimum dalam CMD (+ variabel lingkungan sebagai pengganti).
Kita bisa menginstal bash dan grep penuh di gambar alpine kita (saya akan jelaskan nanti) untuk menghindari sakit kepala dan menggunakan kode asli seperti apa adanya, tetapi itu akan mengembang gambar miniatur kita untuk memalukan, sehingga kita akan tumbuh nyata, ibunya, bonsai.
Mari kita mulai dengan shebang, ganti
#!/bin/bash
dengan
#!/bin/sh
. Default untuk alpine ash mampu mencerna hampir semua sintaks bash "sebagaimana adanya", tetapi kami masih menghadapi satu masalah - untuk alasan yang tidak diketahui, ia menolak menerima tanda kurung dalam salah satu kondisi, oleh karena itu kami akan memperluasnya dengan membalikkan logika perbandingan:

Sekarang kami sedang menunggu showdown dengan grep, yang dalam pengiriman busybox sedikit berbeda dari yang biasa (dan, omong-omong, jauh lebih lambat, ingatlah dalam proyek Anda). Pertama, dia tidak mengerti ungkapan
{,15}
, dia harus secara eksplisit menentukan
{0,15}
. Kedua, itu tidak mendukung flag
-P
(gaya perl), tetapi diam-diam mencerna ekspresi ketika extended (-E) diaktifkan.
Dalam dependensi kami, hanya ada ikal (tidak ada gunanya menggantinya dengan wget dari busybox) dan libcrypto (cukup, langsung openssl tidak diperlukan sama sekali dalam perakitan ini).
Bangunan
multi-tahap yang indah muncul di Docker beberapa tahun yang lalu, sangat ideal, misalnya, untuk aplikasi Go atau untuk situasi di mana perakitannya rumit dan lebih mudah untuk mentransfer artefak dari gambar ke gambar daripada melakukan pembersihan akhir. Kami akan menggunakannya untuk menanam bonsai kami, ini akan menghemat sedikit.
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 . # #
Bonsai harus bonsai - singkirkan instalasi libcrypto. Ketika membangun, kami membutuhkan file header dari paket openssl-dev, yang dalam dependensi akan menarik libcrypto dan executable kami akan berorientasi pada penggunaan libcrypto.so.1.0.0. Tapi ini adalah satu-satunya ketergantungan, selain itu, sudah diinstal di Alpine (dalam versi 3.6 itu libcrypto.so.41, 3.7 - libcrypto.so.42, ini ada di / lib /). Mereka memarahi saya sekarang, ini bukan cara yang paling dapat diandalkan, tapi itu sepadan dan kami masih menambahkan symlink ke versi yang ada (jika Anda memiliki cara yang lebih baik, saya akan dengan senang hati menerima PR).
Sentuhan akhir dan hasil:
Hub dockerGithubSaya akan berterima kasih atas saran dan kontribusi.