
Pada artikel ini, saya ingin berbicara tentang proyek hobi saya pencarian dan klasifikasi iklan untuk menyewa apartemen dari jejaring sosial VKontakte dan pengalaman memindahkannya ke k8s.
Daftar isi
- Sedikit tentang proyek
- Memperkenalkan k8s
- Mempersiapkan langkahnya
- Pengembangan konfigurasi K8
- Penyebaran cluster K8s
Sedikit tentang proyek

Pada bulan Maret 2017, saya meluncurkan layanan untuk penguraian dan klasifikasi iklan untuk menyewa apartemen dari jejaring sosial VKontakte.
Di sini Anda dapat membaca lebih detail tentang bagaimana saya mencoba mengklasifikasikan iklan dengan berbagai cara dan akhirnya memilih pengurai leksikal Yandex Tomita Parser .
Di sini Anda dapat membaca tentang arsitektur proyek di awal keberadaannya dan teknologi apa yang digunakan dan mengapa.
Pengembangan versi pertama dari layanan ini memakan waktu sekitar satu tahun. Untuk menyebarkan setiap komponen layanan, saya menulis skrip dalam Ansible . Dari waktu ke waktu, layanan tidak berfungsi karena kesalahan dalam kode yang didesain ulang atau konfigurasi komponen yang salah.
Sekitar Juni 2019, kesalahan terdeteksi dalam kode parser karena pengumuman baru tidak dikumpulkan. Alih-alih koreksi lain, diputuskan untuk menonaktifkannya sementara.
Alasan untuk pemulihan layanan ini adalah studi tentang K8.
Memperkenalkan k8s
k8s adalah perangkat lunak sumber terbuka untuk mengotomatiskan penyebaran, penskalaan, dan pengelolaan aplikasi kemas.
Seluruh infrastruktur layanan dijelaskan oleh file konfigurasi dalam format yaml (paling sering).
Saya tidak akan berbicara tentang struktur internal k8, tetapi hanya memberikan beberapa informasi tentang beberapa komponennya.
Komponen K8
- Pod adalah unit terkecil. Ini mungkin berisi beberapa kontainer yang akan diluncurkan pada node yang sama.
Wadah di dalam pod:
- memiliki jaringan yang sama dan dapat saling mengakses melalui 127.0.0.1:$containerPort;
- tidak memiliki sistem file yang umum, jadi Anda tidak dapat secara langsung menulis file dari satu wadah ke wadah lainnya.
- Deployment - memantau pekerjaan Pod. Itu dapat meningkatkan jumlah instance Pod yang diperlukan, memulai kembali jika berjatuhan, dan menggunakan Pods baru.
- PersistentVolumeClaim - gudang data. Secara default, ini bekerja dengan sistem file simpul lokal. Oleh karena itu, jika Anda ingin dua Pod berbeda pada node yang berbeda memiliki sistem file yang sama, maka Anda harus menggunakan sistem file jaringan seperti Ceph .
- Layanan - permintaan proxy ke dan dari Pod.
Jenis Layanan:
- LoadBalancer - untuk interaksi dengan jaringan eksternal dengan penyeimbangan beban antara beberapa Pod;
- NodePort (hanya 30000-32767 port) - untuk interaksi dengan jaringan eksternal tanpa load balancing;
- ClusterIp - untuk interaksi di jaringan lokal cluster;
- ExternalName - untuk interaksi antara Pod dan layanan eksternal.
- ConfigMap - penyimpanan konfigurasi.
Agar k8 memulai ulang Pod dengan konfigurasi baru saat ConfigMap berubah, Anda harus menunjukkan versi atas nama ConfigMap Anda dan mengubahnya setiap kali ConfigMap berubah.
Hal yang sama berlaku untuk Rahasia.
Contoh konfigurasi dengan ConfigMapcontainers: - name: collect-consumer image: mrsuh/rent-collector:1.3.1 envFrom: - configMapRef: name: collector-configmap-1.1.0 - secretRef: name: collector-secrets-1.0.0
- Rahasia - penyimpanan konfigurasi rahasia (kata sandi, kunci, token).
- Label - pasangan kunci / nilai yang ditetapkan untuk komponen k8, misalnya, Pod.
Pada awal berkenalan dengan k8s mungkin tidak sepenuhnya jelas cara menggunakan Label. Berikut adalah konfigurasi yang menjelaskan prinsip-prinsip dasar bekerja dengan Label:
Contoh konfigurasi dengan Label apiVersion: apps/v1 kind: Deployment # Deployment metadata: name: deployment-name # Deployment labels: app: deployment-label-app # Label Deployment spec: selector: matchLabels: app: pod-label-app # Label, Deployment Pods template: metadata: name: pod-name labels: app: pod-label-app # Label Pod spec: containers: - name: container-name image: mrsuh/rent-parser:1.0.0 ports: - containerPort: 9080 --- apiVersion: v1 kind: Service # Service metadata: name: service-name # Service labels: app: service-label-app # Label Service spec: selector: # Service matchLabels, Deployment, Labels app: pod-label-app # Label, Service , Pod ports: - protocol: TCP port: 9080 type: NodePort
Mempersiapkan langkahnya
Pemangkasan fungsi
Untuk membuat layanan lebih stabil dan dapat diprediksi, saya harus menghapus semua komponen tambahan yang bekerja dengan buruk dan menulis ulang yang utama sedikit.
Jadi, saya memutuskan untuk menolak:
- kode parsing untuk situs selain VK;
- meminta komponen proxy;
- komponen pemberitahuan pengumuman baru di VKontakte dan Telegram.
Komponen Layanan
Setelah semua perubahan, layanan dari dalam mulai terlihat seperti ini:

- lihat - cari dan tampilkan iklan di situs (NodeJS);
- parser - pengelompokan iklan (Go);
- kolektor - mengumpulkan, memproses, dan menghapus iklan (PHP):
- cron-explore - tim konsol yang mencari grup di VKontakte untuk menyewakan perumahan;
- cron-collect - perintah konsol yang masuk ke grup yang disusun oleh cron-explore dan mengumpulkan iklan sendiri;
- cron-delete - perintah konsol yang menghapus pengumuman yang kadaluwarsa;
- consumer-parse - penangan antrian, yang menerima pekerjaan dari cron-collect. Ini mengklasifikasikan iklan menggunakan komponen parser;
- Consumer-collect - penangan antrian yang mendapat pekerjaan dari parse konsumen. Ini memfilter iklan yang buruk dan duplikat.
Bangun Gambar Docker
Untuk mengelola komponen dan memonitornya dalam satu gaya, saya memutuskan:
- memasukkan konfigurasi komponen ke dalam variabel env,
- tulis log di stdout.
Tidak ada yang spesifik dalam gambar itu sendiri.
Pengembangan konfigurasi K8
Jadi saya mendapatkan komponen dalam gambar Docker, dan saya mulai mengembangkan konfigurasi k8s.
Semua komponen yang berfungsi sebagai daemon disorot di Deployment. Setiap daemon harus dapat diakses di dalam cluster, sehingga setiap orang memiliki Layanan. Semua tugas yang harus dilakukan bekerja secara berkala di CronJob.
Semua statika (gambar, js, css) disimpan dalam wadah tampilan, dan wadah Nginx harus mendistribusikannya. Kedua wadah berada dalam satu Pod. Sistem file di Pod tidak meraba-raba, tetapi pada awal Pod Anda dapat menyalin semua statika ke folder emptyDir yang umum untuk kedua wadah. Folder ini akan dibagikan untuk wadah yang berbeda, tetapi hanya di dalam satu Pod.
Contoh konfigurasi dengan emptyDir apiVersion: apps/v1 kind: Deployment metadata: name: view spec: selector: matchLabels: app: view replicas: 1 template: metadata: labels: app: view spec: volumes: - name: view-static emptyDir: {} containers: - name: nginx image: mrsuh/rent-nginx:1.0.0 - name: view image: mrsuh/rent-view:1.1.0 volumeMounts: - name: view-static mountPath: /var/www/html lifecycle: postStart: exec: command: ["/bin/sh", "-c", "cp -r /app/web/. /var/www/html"]
Komponen kolektor digunakan dalam Penyebaran dan CronJob.
Semua komponen ini mengakses API VKontakte dan harus menyimpan token akses bersama di suatu tempat.
Untuk ini, saya menggunakan PersistentVolumeClaim, yang saya sambungkan ke setiap Pod. Folder seperti itu akan dibagikan untuk Pod yang berbeda, tetapi hanya di dalam satu simpul.
Contoh konfigurasi dengan PersistentVolumeClaim apiVersion: apps/v1 kind: Deployment metadata: name: collector spec: selector: matchLabels: app: collector replicas: 1 template: metadata: labels: app: collector spec: volumes: - name: collector-persistent-storage persistentVolumeClaim: claimName: collector-pv-claim containers: - name: collect-consumer image: mrsuh/rent-collector:1.3.1 volumeMounts: - name: collector-persistent-storage mountPath: /tokenStorage command: ["php"] args: ["bin/console", "app:consume", "--channel=collect"] - name: parse-consumer image: mrsuh/rent-collector:1.3.1 volumeMounts: - name: collector-persistent-storage mountPath: /tokenStorage command: ["php"] args: ["bin/console", "app:consume", "--channel=parse"]
PersistentVolumeClaim juga digunakan untuk menyimpan data basis data. Akibatnya, kami mendapatkan skema seperti itu (Pod dari satu komponen dikumpulkan dalam blok):

Penyebaran cluster K8s
Untuk memulai, saya menggunakan cluster secara lokal menggunakan Minikube .
Tentu saja, ada beberapa kesalahan, jadi tim banyak membantu saya.
kubectl logs -f pod-name kubectl describe pod pod-name
Setelah saya mempelajari cara menggunakan cluster di Minikube, tidak sulit bagi saya untuk menggunakannya di DigitalOcean.
Kesimpulannya, saya dapat mengatakan bahwa layanan telah stabil selama 2 bulan. Konfigurasi lengkap dapat ditemukan di sini .