Calico untuk jaringan di Kubernetes: pengenalan dan sedikit pengalaman

Calico untuk jaringan di Kubernetes: pengenalan dan sedikit pengalaman

Tujuan artikel ini adalah untuk memperkenalkan kepada pembaca dasar-dasar jaringan dan pengelolaan kebijakan jaringan di Kubernetes, serta plugin Calico pihak ketiga yang memperluas kemampuan standar. Secara keseluruhan, kemudahan konfigurasi dan beberapa fitur akan didemonstrasikan menggunakan contoh nyata dari pengalaman pengoperasian kami.

Pengenalan singkat tentang alat jaringan Kubernetes

Cluster Kubernetes tidak dapat dibayangkan tanpa jaringan. Kami telah menerbitkan materi tentang dasar-dasarnya: β€œPanduan bergambar tentang jaringan di Kubernetes"Dan"Pengantar Kebijakan Jaringan Kubernetes untuk Profesional Keamanan'.

Dalam konteks artikel ini, penting untuk dicatat bahwa K8s sendiri tidak bertanggung jawab atas konektivitas jaringan antara container dan node: untuk ini, berbagai Plugin CNI (Antarmuka Jaringan Kontainer). Lebih lanjut tentang konsep ini kita mereka juga memberitahuku.

Misalnya, plugin yang paling umum adalah Flanel β€” menyediakan konektivitas jaringan penuh antara semua node cluster dengan meningkatkan jembatan pada setiap node, dan menetapkan subnet ke dalamnya. Namun, aksesibilitas yang lengkap dan tidak diatur tidak selalu bermanfaat. Untuk memberikan semacam isolasi minimal di cluster, perlu dilakukan intervensi dalam konfigurasi firewall. Dalam kasus umum, ini ditempatkan di bawah kendali CNI yang sama, itulah sebabnya intervensi pihak ketiga apa pun di iptables dapat disalahartikan atau diabaikan sama sekali.

Dan disediakan β€œout of the box” untuk mengatur manajemen kebijakan jaringan di cluster Kubernetes API Kebijakan Jaringan. Sumber daya ini, didistribusikan melalui namespace yang dipilih, mungkin berisi aturan untuk membedakan akses dari satu aplikasi ke aplikasi lainnya. Ini juga memungkinkan Anda untuk mengonfigurasi aksesibilitas antara pod, lingkungan (namespace) atau blok alamat IP tertentu:

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 bukanlah contoh yang paling primitif dokumentasi resmi mungkin sekali dan untuk selamanya mengecilkan keinginan untuk memahami logika bagaimana kebijakan jaringan bekerja. Namun, kami masih akan mencoba memahami prinsip dasar dan metode pemrosesan arus lalu lintas menggunakan kebijakan jaringan...

Masuk akal jika ada 2 jenis lalu lintas: masuk ke pod (Ingress) dan keluar dari pod (Egress).

Calico untuk jaringan di Kubernetes: pengenalan dan sedikit pengalaman

Sebenarnya politik terbagi menjadi 2 kategori tersebut berdasarkan arah pergerakannya.

Atribut wajib berikutnya adalah pemilih; orang yang menerima peraturan tersebut. Ini bisa berupa sebuah pod (atau sekelompok pod) atau sebuah lingkungan (yaitu namespace). Detail penting: kedua jenis objek ini harus berisi label (label dalam terminologi Kubernetes) - inilah yang digunakan oleh para politisi.

Selain jumlah pemilih yang terbatas yang disatukan oleh beberapa jenis label, aturan seperti "Izinkan/tolak semuanya/semua orang" dapat ditulis dalam variasi yang berbeda. Untuk tujuan ini, konstruksi formulir digunakan:

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

β€” dalam contoh ini, semua pod di lingkungan diblokir dari lalu lintas masuk. Perilaku sebaliknya dapat dicapai dengan konstruksi berikut:

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

Demikian pula untuk keluar:

  podSelector: {}
  policyTypes:
  - Egress

- untuk mematikannya. Dan inilah yang harus disertakan:

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

Kembali ke pilihan plugin CNI untuk sebuah cluster, perlu diperhatikan hal itu tidak semua plugin jaringan mendukung NetworkPolicy. Misalnya, Flanel yang telah disebutkan tidak tahu cara mengkonfigurasi kebijakan jaringan, yang mana itu dikatakan secara langsung di repositori resmi. Sebuah alternatif juga disebutkan di sana - proyek Open Source Belacu, yang secara signifikan memperluas kumpulan standar API Kubernetes dalam hal kebijakan jaringan.

Calico untuk jaringan di Kubernetes: pengenalan dan sedikit pengalaman

Mengenal Calico: teori

Plugin Calico dapat digunakan dalam integrasi dengan Flannel (subproyek Kanal) atau secara mandiri, mencakup konektivitas jaringan dan kemampuan manajemen ketersediaan.

Peluang apa yang disediakan oleh penggunaan solusi β€œkotak” K8 dan set API dari Calico?

Inilah yang ada di dalam NetworkPolicy:

  • politisi dibatasi oleh lingkungan;
  • kebijakan diterapkan pada pod yang ditandai dengan label;
  • aturan dapat diterapkan pada pod, lingkungan, atau subnet;
  • aturan dapat berisi protokol, spesifikasi port bernama atau simbolis.

Inilah cara Calico memperluas fungsi-fungsi ini:

  • kebijakan dapat diterapkan pada objek apa pun: pod, container, mesin virtual, atau antarmuka;
  • aturan dapat berisi tindakan tertentu (larangan, izin, pencatatan);
  • target atau sumber aturan dapat berupa port, rentang port, protokol, atribut HTTP atau ICMP, IP atau subnet (generasi ke-4 atau ke-6), penyeleksi apa pun (node, host, lingkungan);
  • Selain itu, Anda dapat mengatur lalu lintas menggunakan pengaturan DNAT dan kebijakan penerusan lalu lintas.

Komit pertama pada GitHub di repositori Calico dimulai pada Juli 2016, dan setahun kemudian proyek ini mengambil posisi terdepan dalam mengatur konektivitas jaringan Kubernetes - hal ini dibuktikan, misalnya, dengan hasil survei, dilakukan oleh The New Stack:

Calico untuk jaringan di Kubernetes: pengenalan dan sedikit pengalaman

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

Untuk performa, semuanya bagus di sini. Dalam pengujian produk mereka, tim pengembangan Calico menunjukkan kinerja luar biasa, menjalankan lebih dari 50000 kontainer pada 500 node fisik dengan tingkat pembuatan 20 kontainer per detik. Tidak ada masalah yang teridentifikasi dengan penskalaan. Hasil seperti itu diumumkan sudah pada pengumuman versi pertama. Studi independen yang berfokus pada throughput dan konsumsi sumber daya juga mengonfirmasi bahwa kinerja Calico hampir sama baiknya dengan Flannel. Misalnya:

Calico untuk jaringan di Kubernetes: pengenalan dan sedikit pengalaman

Proyek ini berkembang sangat cepat, mendukung pekerjaan dalam solusi populer yang dikelola K8, OpenShift, OpenStack, dimungkinkan untuk menggunakan Calico saat menyebarkan cluster menggunakan tendangan, terdapat referensi pembangunan jaringan Service Mesh (Berikut ini adalah contoh digunakan bersama dengan Istio).

Berlatih dengan Calico

Dalam kasus umum penggunaan vanilla Kubernetes, instalasi CNI dilakukan dengan menggunakan file tersebut calico.yaml, diunduh dari situs resminya, ΠΎΠΌΠΎΡ‰ΡŒΡŽ kubectl apply -f.

Biasanya, versi plugin saat ini kompatibel dengan 2-3 versi terbaru Kubernetes: pengoperasian di versi yang lebih lama tidak diuji dan tidak dijamin. Menurut pengembangnya, Calico berjalan pada kernel Linux di atas 3.10 yang menjalankan CentOS 7, Ubuntu 16 atau Debian 8, di atas iptables atau IPVS.

Isolasi dalam lingkungan

Untuk pemahaman umum, mari kita lihat kasus sederhana untuk memahami bagaimana kebijakan jaringan dalam notasi Calico berbeda dari kebijakan standar dan bagaimana pendekatan untuk membuat aturan menyederhanakan keterbacaan dan fleksibilitas konfigurasinya:

Calico untuk jaringan di Kubernetes: pengenalan dan sedikit pengalaman

Ada 2 aplikasi web yang dikerahkan di cluster: di Node.js dan PHP, salah satunya menggunakan Redis. Untuk memblokir akses ke Redis dari PHP, sambil menjaga konektivitas dengan Node.js, cukup terapkan 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

Pada dasarnya kami mengizinkan lalu lintas masuk ke port Redis dari Node.js. Dan mereka jelas tidak melarang hal lain. Segera setelah NetworkPolicy muncul, semua pemilih yang disebutkan di dalamnya mulai diisolasi, kecuali ditentukan lain. Namun, aturan isolasi tidak berlaku untuk objek lain yang tidak tercakup oleh pemilih.

Contohnya menggunakan apiVersion Kubernet sudah siap digunakan, tetapi tidak ada yang menghalangi Anda untuk menggunakannya sumber daya dengan nama yang sama dari pengiriman Calico. Sintaksnya lebih detail, 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 untuk mengizinkan atau menolak semua lalu lintas melalui NetworkPolicy API reguler berisi konstruksi dengan tanda kurung yang sulit untuk dipahami dan diingat. Dalam kasus Calico, untuk mengubah logika aturan firewall menjadi sebaliknya, ubah saja action: Allow pada action: Deny.

Isolasi oleh lingkungan

Sekarang bayangkan situasi di mana aplikasi menghasilkan metrik bisnis untuk dikumpulkan di Prometheus dan dianalisis lebih lanjut menggunakan Grafana. Unggahan tersebut mungkin berisi data sensitif, yang lagi-lagi dapat dilihat publik secara default. Mari kita sembunyikan data ini dari pengintaian:

Calico untuk jaringan di Kubernetes: pengenalan dan sedikit pengalaman

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

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

Lapangan metadata.labels ini ternyata bukan suatu kebetulan. Seperti disebutkan di atas, namespaceSelector (sebaik podSelector) beroperasi dengan label. Oleh karena itu, agar metrik dapat diambil dari semua pod pada port tertentu, Anda harus menambahkan beberapa jenis label (atau mengambil dari yang sudah ada), lalu 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, sintaksnya akan seperti ini:

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 disengaja dalam pengoperasian aplikasi di cluster.

Praktik terbaiknya, menurut pencipta Calico, adalah pendekatan β€œBlokir semuanya dan buka secara eksplisit apa yang Anda perlukan”, yang didokumentasikan dalam dokumentasi resmi (yang lain mengikuti pendekatan serupa - khususnya, di artikel yang sudah disebutkan).

Menggunakan Objek Calico Tambahan

Izinkan saya mengingatkan Anda bahwa melalui rangkaian Calico API yang diperluas, Anda dapat mengatur ketersediaan node, tidak terbatas pada pod. Dalam contoh berikut menggunakan GlobalNetworkPolicy kemampuan untuk meneruskan permintaan ICMP di cluster ditutup (misalnya, ping dari pod ke node, antar pod, atau dari node ke IP pod):

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 mungkin untuk β€œmenjangkau” satu sama lain melalui ICMP. Dan masalah ini diselesaikan dengan cara GlobalNetworkPolicy, diterapkan pada suatu 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"]

Kasus VPN

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

Calico untuk jaringan di Kubernetes: pengenalan dan sedikit pengalaman

Klien terhubung ke VPN melalui port UDP standar 1194 dan, ketika terhubung, menerima rute ke subnet cluster dari pod dan layanan. Seluruh subnet didorong agar tidak kehilangan layanan selama restart dan perubahan alamat.

Port dalam konfigurasinya adalah standar, yang memberikan beberapa nuansa pada proses konfigurasi aplikasi dan mentransfernya ke cluster Kubernetes. Misalnya, dalam hal yang sama AWS LoadBalancer untuk UDP muncul secara harfiah pada akhir tahun lalu di daftar wilayah yang terbatas, dan NodePort tidak dapat digunakan karena penerusannya pada semua node cluster dan tidak mungkin untuk menskalakan jumlah instans server untuk tujuan toleransi kesalahan. Selain itu, Anda harus mengubah rentang port default...

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

  1. Pod dengan VPN dijadwalkan per node di dalamnya hostNetwork, yaitu ke IP sebenarnya.
  2. Layanan ini diposting di luar melalui ClusterIP. Sebuah port dipasang secara fisik pada node, yang dapat diakses dari luar dengan sedikit reservasi (keberadaan alamat IP asli bersyarat).
  3. Menentukan titik dimana pod tumbuh berada di luar cakupan cerita kita. Saya hanya akan mengatakan bahwa Anda dapat dengan ketat "memaku" layanan ke sebuah node atau menulis layanan sespan kecil yang akan memantau alamat IP layanan VPN saat ini dan mengedit catatan DNS yang terdaftar dengan klien - siapa pun yang memiliki cukup imajinasi.

Dari perspektif perutean, kami dapat secara unik mengidentifikasi klien VPN berdasarkan alamat IP yang dikeluarkan oleh server VPN. Di bawah ini adalah contoh primitif dalam membatasi akses klien ke layanan, yang diilustrasikan pada 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, koneksi ke port 6379 sangat dilarang, tetapi pengoperasian layanan DNS dipertahankan, yang fungsinya cukup sering terganggu saat menyusun aturan. Karena, seperti disebutkan sebelumnya, ketika pemilih muncul, kebijakan penolakan default diterapkan padanya kecuali ditentukan lain.

Hasil

Jadi, dengan menggunakan API canggih Calico, Anda dapat secara fleksibel mengonfigurasi dan mengubah perutean secara dinamis di dalam dan di sekitar cluster. Secara umum, penggunaannya terlihat seperti menembak burung pipit dengan meriam, dan mengimplementasikan jaringan L3 dengan terowongan BGP dan IP-IP terlihat mengerikan dalam instalasi Kubernetes sederhana di jaringan datar... Namun, sebaliknya alat ini terlihat cukup layak dan berguna .

Mengisolasi cluster untuk memenuhi persyaratan keamanan mungkin tidak selalu dapat dilakukan, dan di sinilah Calico (atau solusi serupa) dapat membantu. Contoh yang diberikan dalam artikel ini (dengan sedikit modifikasi) digunakan di beberapa instalasi klien kami di AWS.

PS

Baca juga di blog kami:

Sumber: www.habr.com

Tambah komentar