Fail setempat apabila memindahkan aplikasi ke Kubernetes

Fail setempat apabila memindahkan aplikasi ke Kubernetes

Apabila membina proses CI/CD menggunakan Kubernetes, kadangkala timbul masalah ketidakserasian antara keperluan infrastruktur baharu dan aplikasi yang dipindahkan kepadanya. Khususnya, pada peringkat membina aplikasi adalah penting untuk mendapatkan 1 imej yang akan digunakan dalam Semua persekitaran projek dan kelompok. Prinsip ini mendasari yang betul mengikut Google pengurusan kontena (lebih daripada sekali mengenai perkara ini bercakap dan jabatan teknikal kami).

Walau bagaimanapun, anda tidak akan melihat sesiapa pun dalam situasi di mana kod tapak menggunakan rangka kerja sedia, yang penggunaannya mengenakan sekatan ke atas penggunaannya selanjutnya. Dan semasa dalam "persekitaran biasa" perkara ini mudah ditangani, dalam Kubernetes tingkah laku ini boleh menjadi masalah, terutamanya apabila anda menghadapinya buat kali pertama. Walaupun minda inventif boleh menghasilkan penyelesaian infrastruktur yang kelihatan jelas atau baik pada pandangan pertama... adalah penting untuk diingat bahawa kebanyakan situasi boleh dan harus diselesaikan secara seni bina.

Mari lihat penyelesaian penyelesaian yang popular untuk menyimpan fail yang boleh membawa kepada akibat yang tidak menyenangkan apabila mengendalikan kluster, dan juga menunjukkan laluan yang lebih betul.

Storan statik

Untuk menggambarkan, pertimbangkan aplikasi web yang menggunakan beberapa jenis penjana statik untuk mendapatkan set imej, gaya dan perkara lain. Sebagai contoh, rangka kerja PHP Yii mempunyai pengurus aset terbina dalam yang menjana nama direktori unik. Sehubungan itu, output ialah satu set laluan untuk tapak statik yang jelas tidak bersilang antara satu sama lain (ini dilakukan atas beberapa sebab - contohnya, untuk menghapuskan pendua apabila berbilang komponen menggunakan sumber yang sama). Jadi, di luar kotak, pada kali pertama anda mengakses modul sumber web, fail statik (sebenarnya, selalunya symlink, tetapi lebih lanjut mengenainya kemudian) dibentuk dan dibentangkan dengan direktori akar biasa yang unik untuk penggunaan ini:

  • webroot/assets/2072c2df/css/…
  • webroot/assets/2072c2df/images/…
  • webroot/assets/2072c2df/js/…

Apakah maksud ini dari segi kluster?

Contoh paling mudah

Mari kita ambil kes yang agak biasa, apabila PHP didahului oleh nginx untuk mengedarkan data statik dan memproses permintaan mudah. Cara paling mudah - Deployment dengan dua bekas:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: site
spec:
  selector:
    matchLabels:
      component: backend
  template:
    metadata:
      labels:
        component: backend
    spec:
      volumes:
        - name: nginx-config
          configMap:
            name: nginx-configmap
      containers:
      - name: php
        image: own-image-with-php-backend:v1.0
        command: ["/usr/local/sbin/php-fpm","-F"]
        workingDir: /var/www
      - name: nginx
        image: nginx:1.16.0
        command: ["/usr/sbin/nginx", "-g", "daemon off;"]
        volumeMounts:
        - name: nginx-config
          mountPath: /etc/nginx/conf.d/default.conf
          subPath: nginx.conf

Dalam bentuk yang dipermudahkan, konfigurasi nginx bermuara kepada yang berikut:

apiVersion: v1
kind: ConfigMap
metadata:
  name: "nginx-configmap"
data:
  nginx.conf: |
    server {
        listen 80;
        server_name _;
        charset utf-8;
        root  /var/www;

        access_log /dev/stdout;
        error_log /dev/stderr;

        location / {
            index index.php;
            try_files $uri $uri/ /index.php?$args;
        }

        location ~ .php$ {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            include fastcgi_params;
        }
    }

Apabila anda mula-mula mengakses tapak, aset muncul dalam bekas PHP. Tetapi dalam kes dua bekas dalam satu pod, nginx tidak tahu apa-apa tentang fail statik ini, yang (mengikut konfigurasi) harus diberikan kepada mereka. Akibatnya, pelanggan akan melihat ralat 404 untuk semua permintaan kepada fail CSS dan JS. Penyelesaian paling mudah di sini ialah mengatur direktori biasa untuk bekas. Pilihan primitif - umum emptyDir:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: site
spec:
  selector:
    matchLabels:
      component: backend
  template:
    metadata:
      labels:
        component: backend
    spec:
      volumes:
        - name: assets
          emptyDir: {}
        - name: nginx-config
          configMap:
            name: nginx-configmap
      containers:
      - name: php
        image: own-image-with-php-backend:v1.0
        command: ["/usr/local/sbin/php-fpm","-F"]
        workingDir: /var/www
        volumeMounts:
        - name: assets
          mountPath: /var/www/assets
      - name: nginx
        image: nginx:1.16.0
        command: ["/usr/sbin/nginx", "-g", "daemon off;"]
        volumeMounts:
        - name: assets
          mountPath: /var/www/assets
        - name: nginx-config
          mountPath: /etc/nginx/conf.d/default.conf
          subPath: nginx.conf

Sekarang fail statik yang dijana dalam bekas dihidangkan oleh nginx dengan betul. Tetapi izinkan saya mengingatkan anda bahawa ini adalah penyelesaian primitif, yang bermaksud ia jauh dari ideal dan mempunyai nuansa dan kekurangannya sendiri, yang dibincangkan di bawah.

Storan yang lebih maju

Sekarang bayangkan situasi di mana pengguna melawat tapak, memuatkan halaman dengan gaya yang tersedia dalam bekas dan semasa dia membaca halaman ini, kami mengerahkan semula bekas itu. Katalog aset telah menjadi kosong dan permintaan kepada PHP diperlukan untuk mula menjana yang baharu. Walau bagaimanapun, walaupun selepas ini, pautan ke statik lama akan menjadi tidak relevan, yang akan membawa kepada ralat dalam memaparkan statik.

Di samping itu, kemungkinan besar kami mempunyai projek yang lebih atau kurang dimuatkan, yang bermaksud bahawa satu salinan aplikasi tidak akan mencukupi:

  • Mari kita besarkan Deployment sehingga dua replika.
  • Apabila tapak pertama kali diakses, aset telah dibuat dalam satu replika.
  • Pada satu ketika, kemasukan memutuskan (untuk tujuan pengimbangan beban) untuk menghantar permintaan kepada replika kedua, dan aset ini belum ada lagi. Atau mungkin mereka sudah tiada kerana kita gunakan RollingUpdate dan pada masa ini kami sedang melakukan penempatan.

Secara umum, hasilnya sekali lagi kesilapan.

Untuk mengelakkan kehilangan aset lama, anda boleh menukar emptyDir pada hostPath, menambah statik secara fizikal pada nod kelompok. Pendekatan ini tidak baik kerana kita sebenarnya terpaksa mengikat pada nod kluster tertentu aplikasi anda, kerana - sekiranya berpindah ke nod lain - direktori tidak akan mengandungi fail yang diperlukan. Atau beberapa jenis penyegerakan direktori latar belakang antara nod diperlukan.

Apakah penyelesaiannya?

  1. Jika perkakasan dan sumber membenarkan, anda boleh menggunakan cephfs untuk mengatur direktori yang sama boleh diakses untuk keperluan statik. Dokumentasi rasmi mengesyorkan pemacu SSD, sekurang-kurangnya replikasi tiga kali ganda dan sambungan "tebal" yang stabil antara nod kluster.
  2. Pilihan yang kurang menuntut ialah mengatur pelayan NFS. Walau bagaimanapun, maka anda perlu mengambil kira kemungkinan peningkatan dalam masa tindak balas untuk memproses permintaan oleh pelayan web, dan toleransi kesalahan akan meninggalkan banyak perkara yang diingini. Akibat daripada kegagalan adalah malapetaka: kehilangan gunung itu menyebabkan gugusan itu mati di bawah tekanan beban LA yang meluru ke langit.

Antara lain, semua pilihan untuk mencipta storan berterusan akan diperlukan pembersihan latar belakang set fail lapuk yang terkumpul dalam tempoh masa tertentu. Di hadapan bekas dengan PHP anda boleh meletakkan DaemonSet daripada caching nginx, yang akan menyimpan salinan aset untuk masa yang terhad. Tingkah laku ini mudah dikonfigurasikan menggunakan proxy_cache dengan kedalaman storan dalam hari atau gigabait ruang cakera.

Menggabungkan kaedah ini dengan sistem fail yang diedarkan yang disebutkan di atas menyediakan medan yang besar untuk imaginasi, hanya terhad oleh bajet dan potensi teknikal mereka yang akan melaksanakan dan menyokongnya. Dari pengalaman, kita boleh mengatakan bahawa lebih mudah sistem, lebih stabil ia berfungsi. Apabila lapisan sedemikian ditambah, ia menjadi lebih sukar untuk mengekalkan infrastruktur, dan pada masa yang sama masa yang dihabiskan untuk mendiagnosis dan memulihkan daripada sebarang kegagalan meningkat.

Cadangan

Jika pelaksanaan pilihan storan yang dicadangkan juga kelihatan tidak wajar kepada anda (rumit, mahal...), maka ia patut melihat keadaan dari sisi lain. Iaitu, untuk menggali seni bina projek dan selesaikan masalah dalam kod, terikat pada beberapa struktur data statik dalam imej, takrifan yang jelas tentang kandungan atau prosedur untuk "memanaskan badan" dan/atau prapengumpulan aset pada peringkat pemasangan imej. Dengan cara ini kita mendapat tingkah laku yang boleh diramal dan set fail yang sama untuk semua persekitaran dan replika aplikasi yang sedang berjalan.

Jika kita kembali kepada contoh khusus dengan rangka kerja Yii dan tidak menyelidiki strukturnya (yang bukan tujuan artikel), sudah cukup untuk menunjukkan dua pendekatan popular:

  1. Tukar proses binaan imej untuk meletakkan aset di lokasi yang boleh diramal. Ini dicadangkan/dilaksanakan dalam sambungan seperti yii2-aset-statik.
  2. Tentukan cincang khusus untuk direktori aset, seperti yang dibincangkan dalam mis. pembentangan ini (bermula dari slaid No. 35). Dengan cara ini, pengarang laporan akhirnya (dan bukan tanpa sebab!) menasihati bahawa selepas memasang aset pada pelayan binaan, muat naiknya ke storan pusat (seperti S3), di hadapannya meletakkan CDN.

Fail yang boleh dimuat turun

Satu lagi kes yang pasti akan dimainkan apabila memindahkan aplikasi ke gugusan Kubernetes ialah menyimpan fail pengguna dalam sistem fail. Sebagai contoh, kami sekali lagi mempunyai aplikasi PHP yang menerima fail melalui borang muat naik, melakukan sesuatu dengannya semasa operasi dan menghantarnya kembali.

Dalam Kubernetes, lokasi di mana fail ini harus diletakkan hendaklah sama dengan semua replika aplikasi. Bergantung pada kerumitan aplikasi dan keperluan untuk mengatur kegigihan fail ini, pilihan peranti kongsi yang disebutkan di atas mungkin seperti tempat, tetapi, seperti yang kita lihat, ia mempunyai kelemahannya.

Cadangan

Satu penyelesaian ialah menggunakan storan serasi S3 (walaupun ia sejenis kategori yang dihoskan sendiri seperti minio). Beralih kepada S3 memerlukan perubahan pada peringkat kod, dan cara kandungan akan dihantar di bahagian hadapan, kami sudah pun melakukannya писали.

Sesi pengguna

Secara berasingan, perlu diperhatikan organisasi penyimpanan sesi pengguna. Selalunya ini juga fail pada cakera, yang dalam konteks Kubernetes akan membawa kepada permintaan kebenaran berterusan daripada pengguna jika permintaannya berakhir dalam bekas lain.

Masalah ini sebahagiannya diselesaikan dengan menghidupkan stickySessions pada kemasukan (ciri ini disokong dalam semua pengawal kemasukan popular - untuk butiran lanjut, lihat kajian kami)untuk mengikat pengguna ke pod tertentu dengan aplikasi:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx-test
  annotations:
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "route"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"

spec:
  rules:
  - host: stickyingress.example.com
    http:
      paths:
      - backend:
          serviceName: http-svc
          servicePort: 80
        path: /

Tetapi ini tidak akan menghapuskan masalah dengan penggunaan berulang.

Cadangan

Cara yang lebih betul ialah dengan memindahkan aplikasi ke menyimpan sesi dalam memcached, Redis dan penyelesaian yang serupa - secara amnya, tinggalkan sepenuhnya pilihan fail.

Kesimpulan

Penyelesaian infrastruktur yang dibincangkan dalam teks hanya layak digunakan dalam format "tongkat" sementara (yang kelihatan lebih cantik dalam bahasa Inggeris sebagai penyelesaian). Ia mungkin relevan pada peringkat pertama memindahkan aplikasi ke Kubernetes, tetapi tidak seharusnya berakar.

Laluan umum yang disyorkan adalah untuk menyingkirkannya memihak kepada pengubahsuaian seni bina aplikasi mengikut apa yang sudah diketahui ramai Apl 12-Faktor. Walau bagaimanapun, ini - membawa permohonan kepada bentuk tanpa kewarganegaraan - tidak dapat tidak bermakna bahawa perubahan dalam kod akan diperlukan, dan di sini adalah penting untuk mencari keseimbangan antara keupayaan/keperluan perniagaan dan prospek untuk melaksanakan dan mengekalkan laluan yang dipilih .

PS

Baca juga di blog kami:

Sumber: www.habr.com

Tambah komen