Calico untuk berjejaring di Kubernetes: berkenalan dan sedikit pengalaman



Tujuan artikel ini adalah untuk memperkenalkan pembaca pada dasar-dasar jaringan dan mengelola kebijakan jaringan di Kubernetes, serta plug-in Calico pihak ketiga yang memperluas fitur standar. Sepanjang jalan, kenyamanan konfigurasi dan beberapa fitur akan ditunjukkan pada contoh nyata dari pengalaman operasi kami.

Pengantar cepat ke perangkat jaringan Kubernetes


Cluster Kubernetes tidak dapat dibayangkan tanpa jaringan. Kami telah menerbitkan materi tentang dasar-dasar mereka: " Sebuah Panduan Ilustrasi untuk Jaringan di Kubernetes " dan " Pengantar Kebijakan Jaringan Kubernetes untuk Profesional Keamanan ".

Dalam konteks artikel ini, penting untuk dicatat bahwa K8 tidak bertanggung jawab atas konektivitas jaringan antara kontainer dan node: semua jenis plugin CNI (Container Networking Interface) digunakan untuk ini. Kami juga berbicara lebih banyak tentang konsep ini.

Misalnya, yang paling umum dari plug-in ini - Flannel - menyediakan konektivitas jaringan penuh antara semua node cluster dengan mengangkat jembatan pada setiap node, mengamankan subnet untuk itu. Namun, ketersediaan penuh dan tidak diatur tidak selalu berguna. Untuk memberikan beberapa isolasi minimal dalam cluster, perlu campur tangan dalam konfigurasi firewall. Dalam kasus umum, ini diberikan kepada manajemen CNI, karena gangguan pihak ketiga dalam iptables dapat diartikan salah atau diabaikan sama sekali.

Dan di luar kotak, NetworkPolicy API disediakan untuk mengatur manajemen kebijakan jaringan di kluster Kubernetes. Sumber daya ini, yang meluas ke ruang nama yang dipilih, dapat berisi aturan untuk membatasi akses dari satu aplikasi ke aplikasi lainnya. Ini juga memungkinkan Anda untuk mengkonfigurasi aksesibilitas antara pod, lingkungan (ruang nama) tertentu atau blok alamat IP:

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: test-network-policy namespace: default spec: podSelector: matchLabels: role: db policyTypes: - Ingress - Egress ingress: - from: - ipBlock: cidr: 172.17.0.0/16 except: - 172.17.1.0/24 - namespaceSelector: matchLabels: project: myproject - podSelector: matchLabels: role: frontend ports: - protocol: TCP port: 6379 egress: - to: - ipBlock: cidr: 10.0.0.0/24 ports: - protocol: TCP port: 5978 

Ini bukan contoh paling primitif dari dokumentasi resmi yang dapat sekali dan untuk semua mencegah keinginan untuk memahami logika kebijakan jaringan. Namun, kami masih mencoba memahami prinsip dasar dan metode pemrosesan arus lalu lintas menggunakan kebijakan jaringan ...

Adalah logis bahwa ada 2 jenis lalu lintas: masuk ke pod (Ingress) dan keluar darinya (Egress).



Sebenarnya, politik dibagi menjadi 2 kategori ini dalam arah gerakan.

Atribut yang diperlukan berikutnya adalah pemilih; orang yang aturannya berlaku. Itu bisa berupa pod (atau grup pod) atau lingkungan (mis. Namespace). Detail penting: kedua jenis objek ini harus mengandung label ( label dalam terminologi Kubernetes) - ini adalah kebijakan yang beroperasi.

Selain jumlah pemilih terbatas yang disatukan oleh beberapa label, ada kemungkinan aturan penulisan seperti "Izinkan / Tolak Semua / Semua" dalam variasi yang berbeda. Untuk ini, konstruksi bentuk digunakan:

  podSelector: {} ingress: [] policyTypes: - Ingress 

- dalam contoh ini, semua pod lingkungan menutup lalu lintas masuk. Perilaku yang berlawanan dapat dicapai dengan konstruksi seperti itu:

  podSelector: {} ingress: - {} policyTypes: - Ingress 

Demikian pula untuk keluar:

  podSelector: {} policyTypes: - Egress 

- untuk menonaktifkannya. Dan inilah yang termasuk:

  podSelector: {} egress: - {} policyTypes: - Egress 

Kembali ke pilihan plugin CNI untuk sebuah cluster, perlu dicatat bahwa tidak setiap plugin jaringan mendukung bekerja dengan NetworkPolicy . Misalnya, Flannel yang sudah disebutkan tidak tahu cara mengkonfigurasi kebijakan jaringan, seperti yang secara eksplisit dinyatakan dalam repositori resmi. Alternatif juga disebutkan di sana - proyek Open Source Calico , yang secara signifikan memperluas API Kubernetes standar dalam hal kebijakan jaringan.



Temui Calico: Teori


Plugin Calico dapat digunakan dalam integrasi dengan Flannel (proyek Canal ) atau sendiri, yang mencakup konektivitas jaringan dan fitur manajemen ketersediaan.

Fitur apa yang disediakan oleh solusi kotak K8 dan Calico API set?

Inilah yang dibangun ke dalam NetworkPolicy:

  • politisi dibatasi oleh lingkungan;
  • Kebijakan berlaku untuk pod yang ditandai dengan label.
  • aturan dapat diterapkan ke pod, lingkungan atau subnet;
  • aturan dapat berisi protokol, nama atau instruksi port simbolik.

Dan inilah cara Calico memperluas fitur-fitur ini:

  • kebijakan dapat diterapkan ke objek apa pun: pod, wadah, mesin virtual, atau antarmuka;
  • aturan dapat berisi tindakan spesifik (larangan, izin, penebangan);
  • target atau sumber aturan dapat berupa port, jangkauan port, protokol, atribut HTTP atau ICMP, IP atau subnet (generasi 4 atau 6), setiap penyeleksi (node, host, lingkungan);
  • Selain itu, arus lalu lintas dapat dikontrol menggunakan pengaturan DNAT dan kebijakan penerusan lalu lintas.

GitHub pertama berkomitmen dalam repositori Calico kembali ke Juli 2016, dan setahun kemudian proyek mengambil posisi terdepan dalam organisasi konektivitas jaringan Kubernetes - ini ditunjukkan, misalnya, oleh hasil survei yang dilakukan oleh The New Stack :



Banyak solusi besar yang dikelola dengan K8, seperti Amazon EKS , Azure AKS , Google GKE dan lainnya, mulai merekomendasikannya untuk digunakan.

Adapun kinerja, semuanya bagus di sini. Saat menguji produknya, tim pengembang Calico mendemonstrasikan kinerja astronomi dengan meluncurkan lebih dari 50.000 kontainer pada 500 node fisik dengan kecepatan menciptakan 20 kontainer per detik. Tidak ada masalah dengan penskalaan. Hasil seperti itu sudah diumumkan pada pengumuman versi pertama. Penelitian independen tentang bandwidth dan konsumsi sumber daya juga mengkonfirmasi kinerja Calico, yang hampir sama dengan Flannel. Sebagai contoh :



Proyek ini berkembang sangat cepat, mendukung kerja dalam solusi populer yang dikelola K8s, OpenShift, OpenStack, dimungkinkan untuk menggunakan Calico ketika menggunakan sebuah cluster menggunakan kops , ada referensi untuk membangun jaringan Service Mesh (di sini adalah contoh menggunakannya dengan Istio).

Berlatih dengan Calico


Dalam kasus umum menggunakan vanilla Kubernetes, menginstal CNI bermuara menggunakan file calico.yaml diunduh dari situs resmi menggunakan kubectl apply -f .

Sebagai aturan, versi plugin saat ini kompatibel dengan 2-3 versi Kubernetes terbaru: bekerja di versi yang lebih lama tidak diuji dan tidak menjamin. Menurut pengembang, Calico berjalan pada kernel Linux di atas 3.10 di bawah CentOS 7, Ubuntu 16 atau Debian 8, di atas iptables atau IPVS.

Isolasi di dalam lingkungan


Untuk pemahaman umum, pertimbangkan kasus sederhana untuk memahami bagaimana kebijakan jaringan dalam notasi Calico berbeda dari yang standar dan bagaimana pendekatan untuk menyusun aturan menyederhanakan keterbacaan dan fleksibilitas konfigurasi:



Ada 2 aplikasi web yang digunakan dalam cluster: Node.js dan PHP, salah satunya menggunakan Redis. Untuk memblokir akses ke Redis dari PHP, sambil meninggalkan konektivitas dengan Node.js, cukup menerapkan kebijakan berikut:

 kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: allow-redis-nodejs spec: podSelector: matchLabels: service: redis ingress: - from: - podSelector: matchLabels: service: nodejs ports: - protocol: TCP port: 6379 

Intinya, kami mengizinkan lalu lintas masuk ke port Redis dari Node.js. Dan jelas mereka tidak melarang hal lain. Segera setelah NetworkPolicy muncul, maka semua pemilih yang disebutkan di dalamnya mulai terisolasi, kecuali dinyatakan sebaliknya. Selain itu, aturan isolasi tidak berlaku untuk objek lain yang tidak dicakup oleh pemilih.

Contoh ini menggunakan apiVersion apiVersion "out of the box", tetapi tidak ada yang mencegah menggunakan sumber daya dengan nama yang sama dari pengiriman Calico . Sintaksnya lebih luas di sana, jadi Anda perlu menulis ulang aturan untuk kasus di atas dalam bentuk berikut:

 apiVersion: crd.projectcalico.org/v1 kind: NetworkPolicy metadata: name: allow-redis-nodejs spec: selector: service == 'redis' ingress: - action: Allow protocol: TCP source: selector: service == 'nodejs' destination: ports: - 6379 

Konstruksi yang disebutkan di atas memungkinkan atau melarang semua lalu lintas melalui API NetworkPolicy yang biasa berisi struktur dengan tanda kurung yang sulit dipahami dan diingat. Dalam kasus Calico, untuk mengubah logika aturan firewall ke arah sebaliknya, cukup ubah action: Allow untuk action: Deny .

Isolasi Lingkungan


Sekarang bayangkan sebuah situasi di mana aplikasi menghasilkan metrik bisnis untuk mengumpulkannya di Prometheus dan analisis lebih lanjut melalui Grafana. Bongkar dapat berisi data sensitif, yang, secara default, tersedia untuk umum lagi. Mari kita tutup data ini dari mengintip:



Prometheus, sebagai suatu peraturan, ditempatkan di lingkungan layanan yang terpisah - dalam contoh, ini akan menjadi namespace dari formulir berikut:

 apiVersion: v1 kind: Namespace metadata: labels: module: prometheus name: kube-prometheus 

Bidang metadata.labels sini tidak disengaja. Seperti disebutkan di atas, namespaceSelector (seperti podSelector ) beroperasi pada label. Karenanya, untuk mengizinkan pengambilan metrik dari semua pod pada port tertentu, Anda harus menambahkan beberapa label (atau mengambil dari yang ada), dan kemudian menerapkan konfigurasi seperti:

 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-metrics-prom spec: podSelector: {} ingress: - from: - namespaceSelector: matchLabels: module: prometheus ports: - protocol: TCP port: 9100 

Dan jika Anda menggunakan kebijakan Calico, sintaksinya adalah:

 apiVersion: crd.projectcalico.org/v1 kind: NetworkPolicy metadata: name: allow-metrics-prom spec: ingress: - action: Allow protocol: TCP source: namespaceSelector: module == 'prometheus' destination: ports: - 9100 

Secara umum, dengan menambahkan kebijakan semacam ini untuk kebutuhan spesifik, Anda dapat melindungi terhadap gangguan berbahaya atau tidak sengaja dalam pengoperasian aplikasi di cluster.

Praktik terbaik, menurut pencipta Calico, adalah pendekatan “Larangkan Segalanya dan Temukan yang Dibutuhkan”, sebagaimana dicatat dalam dokumentasi resmi (yang lain mengikuti pendekatan yang serupa, khususnya, dalam artikel yang telah disebutkan ).

Menggunakan Calico Optional Objects


Biarkan saya mengingatkan Anda bahwa melalui serangkaian API Calico, Anda dapat mengontrol ketersediaan node, tidak terbatas pada pod. Dalam contoh berikut, menggunakan GlobalNetworkPolicy menutup kemungkinan melewati permintaan ICMP di cluster (misalnya, ping dari pod ke node, antara pod atau dari node ke pod IP):

 apiVersion: crd.projectcalico.org/v1 kind: GlobalNetworkPolicy metadata: name: block-icmp spec: order: 200 selector: all() types: - Ingress - Egress ingress: - action: Deny protocol: ICMP egress: - action: Deny protocol: ICMP 

Dalam kasus di atas, node cluster masih dapat "menjangkau" satu sama lain melalui ICMP. Dan pertanyaan ini diselesaikan dengan menggunakan GlobalNetworkPolicy diterapkan pada entitas HostEndpoint :

 apiVersion: crd.projectcalico.org/v1 kind: GlobalNetworkPolicy metadata: name: deny-icmp-kube-02 spec: selector: "role == 'k8s-node'" order: 0 ingress: - action: Allow protocol: ICMP egress: - action: Allow protocol: ICMP --- apiVersion: crd.projectcalico.org/v1 kind: HostEndpoint metadata: name: kube-02-eth0 labels: role: k8s-node spec: interfaceName: eth0 node: kube-02 expectedIPs: ["192.168.2.2"] 

Kasing VPN


Akhirnya, saya akan memberikan contoh nyata tentang penggunaan fungsi Calico untuk kasus dengan interaksi dekat-kluster, ketika serangkaian kebijakan standar tidak cukup. Terowongan VPN digunakan oleh klien untuk mengakses aplikasi web, dan akses ini dikontrol dengan ketat dan terbatas pada daftar layanan tertentu yang diizinkan:



Klien terhubung ke VPN melalui port UDP standar 1194 dan, ketika terhubung, menerima rute ke sub kelompok subnet dari pod dan layanan. Subnet push sepenuhnya agar tidak kehilangan layanan selama restart dan mengatasi perubahan.

Port dalam konfigurasi adalah standar, yang memberikan beberapa nuansa pada proses mengkonfigurasi aplikasi dan transfernya ke cluster Kubernetes. Sebagai contoh, dalam AWS yang sama, LoadBalancer untuk UDP muncul secara harfiah pada akhir tahun lalu dalam daftar terbatas daerah, dan NodePort tidak dapat digunakan karena penerusannya pada semua node cluster dan tidak mungkin untuk skala jumlah contoh server untuk toleransi kesalahan. Plus, Anda harus mengubah kisaran port default ...

Sebagai hasil dari pencarian solusi yang mungkin, yang berikut ini dipilih:

  1. hostNetwork VPN dijadwalkan per host dalam mode hostNetwork , yaitu pada IP aktual.
  2. Layanan diposting melalui ClusterIP . Port secara fisik naik pada host, yang dapat diakses dari luar dengan beberapa peringatan (ketersediaan bersyarat dari alamat IP nyata).
  3. Definisi simpul di mana pod naik berada di luar ruang lingkup cerita kita. Saya hanya bisa mengatakan bahwa Anda dapat dengan kuat "memakukan" layanan ke host atau menulis layanan sespan kecil yang akan memantau alamat IP saat ini dari layanan VPN dan mengedit catatan DNS yang terdaftar dengan klien - yang memiliki imajinasi yang cukup.

Dari sudut pandang perutean, kami dapat secara unik mengidentifikasi klien untuk VPN dengan alamat IP-nya yang dikeluarkan oleh server VPN. Di bawah ini adalah contoh primitif membatasi akses ke klien untuk layanan tersebut, sebuah ilustrasi tentang Redis yang disebutkan di atas:

 apiVersion: crd.projectcalico.org/v1 kind: HostEndpoint metadata: name: vpnclient-eth0 labels: role: vpnclient environment: production spec: interfaceName: "*" node: kube-02 expectedIPs: ["172.176.176.2"] --- apiVersion: crd.projectcalico.org/v1 kind: GlobalNetworkPolicy metadata: name: vpn-rules spec: selector: "role == 'vpnclient'" order: 0 applyOnForward: true preDNAT: true ingress: - action: Deny protocol: TCP destination: ports: [6379] - action: Allow protocol: UDP destination: ports: [53, 67] 

Di sini, sangat dilarang untuk terhubung ke port 6379, tetapi pada saat yang sama, layanan DNS dipertahankan, fungsi yang sering menderita ketika membuat aturan. Karena, seperti yang disebutkan sebelumnya, ketika pemilih muncul, kebijakan standar penghalang diterapkan untuk itu, kecuali ditentukan lain.

Ringkasan


Dengan demikian, menggunakan Calico Advanced API, Anda dapat secara fleksibel mengkonfigurasi dan secara dinamis mengubah perutean di dan di sekitar cluster. Secara umum, penggunaannya mungkin terlihat seperti suara tembakan pada burung pipit, dan pengenalan jaringan L3 dengan BGP dan terowongan IP-IP terlihat mengerikan dalam pemasangan sederhana Kubernetes pada jaringan datar ... Namun, alat lainnya terlihat cukup layak dan bermanfaat.

Isolasi cluster untuk persyaratan keamanan mungkin tidak selalu layak, dan dalam kasus seperti itulah Calico (atau solusi serupa) datang untuk menyelamatkan. Contoh-contoh dalam artikel ini (dengan sedikit perbaikan) digunakan dalam beberapa instalasi klien kami di AWS.

PS


Baca juga di blog kami:

Source: https://habr.com/ru/post/id485716/


All Articles