Kabel Terhubung di Jaringan Kontainer

Giri Kuncoro
Pujangga Teknologi
Published in
10 min readFeb 14, 2019

Kontainer. Teknologi ini jadi populer karena Docker. Namun sebenarnya kontainer sudah cukup lama dikenal di dunia Linux dengan ruangnama (baca: namespace) dan Cgroups. Menurut Docker, kontainer adalah bagian dari perangkat lunak yang membuat aplikasi jadi mudah dijalani. Kontainer membungkus barisan kode dan semua dependensinya, supaya aplikasi bisa cepat dan andal (baca: reliable) jalan di lingkungan (baca: environment) satu dan lainnya.

Salah satu yang sering membuat orang pusing soal kontainer adalah cara kerja jaringannya. Bagaimana bisa banyak kontainer jalan di satu mesin saling terhubung? Bagaimana kontainer di mesin yang satu bisa ngobrol dengan kontainer di mesin yang beda? Ada banyak sekali cara jaringan kontainer bekerja. Artikel ini mencoba mengupas dan mengenalkan teman-teman pembaca pada beberapa model sederhana untuk jaringan kontainer.

Kamus istilah

Catatan istilah-istilah penting pada jaringan kontainer:

  • Ruangnama (namespace): sebuah fitur Linux yang dapat mengisolasi berbagai macam ranah, termasuk jaringan, proses, dan volum.
  • Tuanrumah (host): mesin tempat jalannya kontainer.
  • Rute (route): rute yang memberitahu Linux kemana paket harus diteruskan, biasa ditemukan pada router.
  • Jembatan (bridge): sebuah software yang menghubungkan dua segmen jaringan berbeda.
  • Jaringan overlay (overlay network): sebuah jaringan yang dibuat di atas jaringan lain.

Apa sebenarnya jaringan kontainer?

Saat kode jalan di dalam kontainer, sebenarnya kita punya 2 opsi:

  • Kode jalan di ruangnama jaringan tuan rumah (baca: host network namespace). Ini cukup normal dan mudah dimengerti. Kalau kode jalan di port 3000, di mesin juga akan jalan di port 3000.
  • Kode jalan di ruangnama jaringannya sendiri.

Misalkan kode jalan di ruangnama jaringannya sendiri pada port 5000. Mesin lain tentu harus punya jaringan yang terhubung ke kode tersebut. Awalnya banyak yang mengira, apa sulitnya ini? Bukankah menghubungkan jaringan 2 kode yang berbeda cukup mudah? Rupanya ada banyak solusi. Pada artikel ini, kita akan coba membuat jaringan kontainer terhubung dengan 4 model berbeda. Mulai dari ruangnama tuanrumah yang sederhana, sampai menggunakan model jaringan overlay.

Mengingat kembali konsep jaringan

  • Dalam jaringan komputer, program saling mengirimkan paket.
  • Setiap paket punya alamat IP.
  • Dalam Linux, kernel bertanggung jawab implementasi protokol jaringan.
  • Subnet 172.16.1.0/24 berarti alamat IP dari 172.16.1.0 sampai 172.16.1.255.
  • Jaringan terdiri dari 7 lapisan OSI: Alamat Mac di lapisan 2; asal dan tujuan IP di lapisan 3; port dan info TCP/UDP di lapisan 4; konten dari paket HTTP di layer 7.

Model 1: Terhubung dengan 1 ruangnama jaringan

1 ruangnama jaringan

Gambar di atas menggambarkan model paling sederhana bagaimana kontainer terhubung ke dunia di luarnya. Kontainer kon melalui mekanisme Linux ruangnama dan Cgroups, terisolasi dengan cukup ajaib. Tulisan kali ini tak akan membahas detail bagaimana ruangnama bekerja. Namun, bagian yang paling menarik untuk disimak saat ini adalah ruangnama jaringan. Dengan adanya ruangnama jaringannya sendiri, kontainer memiliki susun jaringan (baca: networking stack) yang terisolasi. Apa artinya? Kontainer jadi punya paling tidak 3 hal: antarmuka jaringannya sendiri, alamat IP sendiri, dan aturan rute sendiri.

Mari kita coba buat ruangnama jaringan. Ambil mesin Linux-mu, dan coba jalankan perintah ini untuk membuat ruangnama jaringan dengan nama kon.

$ ip netns add kon
$ ip netns
kon (id: 0)

Untuk menjalankan perintah di dalam ruangnama tersebut, cukup gunakan perintah ip dengan ruangnama, dilanjutkan dengan perintah yang diinginkan. Coba kita bandingkan antarmuka yang dimiliki oleh ruangnama ini dengan tuanrumah.

$ ip netns exec ip link
1: lo
(tanpa netns, jalan di tuanrumah)
$ ip link
1: lo
2: eth0

Berbeda bukan hasilnya? Ini membuktikan kontainer dan tuanrumah punya antarmuka jaringan yang berbeda, berkat isolasi. Sekarang pertanyaannya, bagaimana cara menghubungkan kontainer dengan tuanrumah kalau begini? Menurut gambar tadi, kita perlu membuat kabel veth yang menyambung ruangnama kontainer dengan tuanrumah. Ujung kabel satu berada di tuanrumah, dan ujung satunya lagi di ruangnama kontainer.

$ ip link add veth1 type veth peer name veth2
$ ip link set veth2 netns kon

Nah, sekarang kita bisa memberi alamat IP ujung veth yang ada di ruangnama kontainer. Asumsi tuanrumah sudah punya IP 10.0.0.10 pada antarmuka utama, coba kita beri alamat IP dengan subnet berbeda pada ruangnama kontainer. Misalnya, 172.16.0.1. Lalu, kita naikkan kedua ujung kabel veth dan antarmuka loopback.

$ ip netns exec kon ip addr add 172.16.0.1 dev veth2$ ip netns exec kon ip link set dev veth2 up
$ ip link set dev veth1 up
$ ip netns exec kon ip link set lo up

Supaya kontainer bisa ngobrol dengan tuanrumah, menaikkan antarmuka saja tidak cukup. Kita harus mengatur rute default di dalam kontainer, dan rute kemana tuanrumah harus mengirimkan paket untuk kontainer kita.

$ ip route add 172.16.0.1/32 dev veth1
$ ip netns exec kon ip route add default via 172.16.0.1 dev veth2

Sekarang, kontainer kita sudah terhubung dan siap ngobrol dengan tuanrumah.

$ ping 172.16.0.1
$ ip netns exec kon ping 10.0.0.1

Kita sudah berhasil menghubungkan ruangnama kontainer dan tuanrumah, dengan bantuan kabel veth dan aturan rute.

Model 2: Terhubung dengan 2 ruangnama, 1 tuanrumah

2 ruangnama, 1 tuanrumah

Model berikutnya, kita punya 2 ruangnama kontainer jalan di dalam 1 tuanrumah. Masing-masing kontainer punya alamat IP berbeda. Seperti layaknya model 1, setiap kontainer terhubung dengan kabel veth. Kali ini kita hubungkan kabel tersebut dengan sebuah jembatan (baca: bridge) br0. Sebenarnya tanpa memberi alamat IP pada jembatan, kedua kontainer ini sudah bisa komunikasi. Tapi untuk bisa sampai ke tuanrumah, jembatan ini perlu IP.

Bagaimana 2 ruangnama yang saling terisolasi ini bisa terhubung? Bagaimana cara mereka ngobrol dengan tuanrumah melalui jembatan? Mari kita simulasikan.

Pertama, kita buat 2 ruangnama jaringan kon1 dan kon2.

$ ip netns add kon1
$ ip netns add kon2
$ ip netns
kon1 (id: 0)
kon2 (id: 1)

Lalu, buat kabel veth seperti di model 1. Simpan satu ujung veth pada ruangnama kontainer, dan ujung satunya pada tuanrumah.

$ ip link add veth10 type veth peer name veth11
$ ip link add veth20 type veth peer name veth21
$ ip link set veth11 netns kon1
$ ip link set veth21 netns kon2

Berikan alamat IP pada ujung veth di ruangnama kontainer dan naikkan.

$ ip netns exec kon1 ip addr add 172.16.0.2/24 dev veth11
$ ip netns exec kon2 ip addr add 172.16.0.3/24 dev veth21
$ ip netns exec kon1 ip link set dev veth11 up
$ ip netns exec kon2 ip link set dev veth21 up

Buat jembatan, berikan alamat IP, dan naikkan semua antarmuka yang belum aktif.

$ ip link add name br0 type bridge$ ip link set dev veth10 master br0
$ ip link set dev veth20 master br0
$ ip addr add 172.16.0.1/24 dev br0
$ ip link set dev br0 up
$ ip link set dev veth10 up
$ ip link set dev veth20 up
$ ip netns exec kon1 ip link set lo up
$ ip netns exec kon2 ip link set lo up

Terakhir, kita konfigurasi rute default pada masing-masing kontainer melalui jembatan br0, supaya mereka tahu jalan menuju tuanrumah.

$ ip netns exec kon1 ip route add default via 172.16.0.1 dev veth11
$ ip netns exec kon2 ip route add default via 172.16.0.1 dev veth21

Sekarang, 2 ruangnama kontainer ini sudah saling terhubung, dan juga siap ngobrol dengan tuanrumah. Coba kita tes koneksi dari kon1 ke kon2.

$ ip netns exec kon1 ping 172.16.0.3

Tes juga koneksi dari kon1 ke tuanrumah, dan dari tuanrumah ke kon2.

$ ip netns exec kon1 ping 10.0.0.1
$ ping 172.16.0.3

Nah, kita sudah berhasil menghubungkan antar kontainer dan juga tuanrumah. Seperti model 1, selain dibantu dengan kabel veth dan aturan rute, model 2 ini menggunakan jembatan br0 untuk menghubungkan beberapa kontainer di tuanrumah yang sama.

Model 3: Terhubung dengan banyak tuanrumah, jaringan L2 sama

Banyak tuanrumah, jaringan L2 sama

Model selanjutnya, kita punya beberapa kontainer yang tersebar di 2 tuanrumah berbeda. Tuanrumah tersebut terhubung di jaringan L2 melalui switch. Bagaimana kontainer di satu tuanrumah bisa ngobrol dengan tuanrumah lainnya? Mari kita coba cari tahu.

Sebenarnya, ini merupakan ekstensi dari model 2 yang sudah kita coba. Namun, kuncinya ada pada rute di masing-masing tuanrumah. Pertama, kita siapkan 2 tuanrumah dengan konfigurasi pada model 2. Untuk mempercepat konfigurasi, jalankan skrip di bawah ini. Sesuaikan alamat IP pada masing-masing tuanrumah.

$ ip netns add $KON1
$ ip netns add $KON2
$ ip link add veth10 type veth peer name veth11
$ ip link add veth20 type veth peer name veth21
$ ip link set veth11 netns $KON1
$ ip link set veth21 netns $KON2
$ ip netns exec $KON1 ip addr add $IP1/24 dev veth11
$ ip netns exec $KON2 ip addr add $IP2/24 dev veth21
$ ip netns exec $KON1 ip link set dev veth11 up
$ ip netns exec $KON2 ip link set dev veth21 up
$ ip link add name br0 type bridge$ ip link set dev veth10 master br0
$ ip link set dev veth20 master br0
$ ip addr add $BRIDGE_IP/24 dev br0$ ip link set dev br0 up$ ip link set dev veth10 up
$ ip link set dev veth20 up
$ ip netns exec $KON1 ip link set lo up
$ ip netns exec $KON2 ip link set lo up
$ ip netns exec $KON1 ip route add default via $BRIDGE_IP dev veth11
$ ip netns exec $KON2 ip route add default via $BRIDGE_IP dev veth21

Sekarang kita sudah punya 2 tuanrumah dengan konfigurasi sama seperti model 2. Asumsi 2 tuanrumah ini sudah terhubung dengan L2 switch. Untuk model ini, kita perlu tambahkan rute spesifik pada tuanrumah untuk bisa ngobrol dengan ruangnama jaringan di tuanrumah satunya.

(pada tuanrumah 1)
$ ip route add 172.16.1.0/24 via 10.0.0.20 dev eth0
(pada tuanrumah 2)
$ ip route add 172.16.0.0/24 via 10.0.0.10 dev eth0

Lalu terakhir, kita harus aktifkan IP forward pada masing-masing tuanrumah. Ini kita perlukan supaya paket yang datang ke antarmuka utama bisa diteruskan oleh Linux ke antarmuka yang lain. Kalau ini tidak dilakukan, paket yang ditujukan ke antarmuka dengan alamat IP yang tidak dimilikinya akan dijatuhkan. Dalam hal ini, antarmuka utama pada tuanrumah akan menerima IP 172.16.*.* yang bukan miliknya, melainkan milik antarmuka br0, sehingga perlu diteruskan.

$ sysctl -w net.ipv4.ip_forward=1

Kita sudah siap untuk tes koneksi. Mari kita coba koneksi dari kon1 ke kon3.

$ ip netns exec kon1 ping 172.16.1.2

Hore! Kita sudah berhasil membuktikan terhubungnya kontainer antar tuanrumah. Dengan terhubungnya tuanrumah melalui L2 switch, kita cukup melakukan pengaturan rute subnet kontainer yang ada di tuanrumah lainnya.

Model 4: Terhubung dengan banyak tuanrumah, jaringan overlay

Banyak tuanrumah, jaringan overlay

Pada model 3, kita sudah pelajari kontainer yang terhubung dengan L2 jaringan sama. Sekarang, bagaimana jadinya bila L2 tersegregasi, atau di antara tuanrumah ada router bahkan ratusan router di jaringan Internet? Tentu model 3 tak akan jalan, karena router di Internet tak tahu menahu soal alamat IP subnet kontainer. Lalu bagaimana solusinya? Ada banyak solusi, salah satunya dengan jaringan overlay.

Di model 4 ini, kita tambahkan antarmuka tun seperti pada gambar di atas. Antarmuka tun ini cukup unik, karena di belakangnya tidak ada apa-apa, nampak kosongan saja. Namun, ini berguna jika kita jalankan proses/program di belakangnya.

Antarmuka tun akan menerima paket mentah, lalu program bisa melakukan apapun terhadap paket ini. Dalam kasus ini, program bisa membungkus paket dengan paket UDP misalnya, alias enkapsulasi, lalu dikirim ke tuanrumah lain. Ini ide dasar dari mekanisme jaringan overlay. Gunanya? Tuanrumah tak perlu tahu soal jaringan kontainer, tapi cukup tahu bagaimana terhubung dengan tuanrumah yang lain.

Mari kita coba simulasikan. Langkah pertama, siapkan 2 tuanrumah dan jalankan perintah yang mirip dengan model 3 di masing-masing tuan rumah berikut.

$ ip netns add $KON1
$ ip netns add $KON2
$ ip link add veth10 type veth peer name veth11
$ ip link add veth20 type veth peer name veth21
$ ip link set veth11 netns $KON1
$ ip link set veth21 netns $KON2
$ ip netns exec $KON1 ip addr add $IP1/24 dev veth11
$ ip netns exec $KON2 ip addr add $IP2/24 dev veth21
$ ip netns exec $KON1 ip link set dev veth11 up
$ ip netns exec $KON2 ip link set dev veth21 up
$ ip link add name br0 type bridge$ ip link set dev veth10 master br0
$ ip link set dev veth20 master br0
$ ip addr add $BRIDGE_IP/24 dev br0$ ip link set dev br0 up$ ip link set dev veth10 up
$ ip link set dev veth20 up
$ ip netns exec $KON1 ip link set lo up
$ ip netns exec $KON2 ip link set lo up
$ ip netns exec $KON1 ip route add default via $BRIDGE_IP dev veth11
$ ip netns exec $KON2 ip route add default via $BRIDGE_IP dev veth21
$ sysctl -w net.ipv4.ip_forward=1

Dari sini, kita akan membuat terowongan (baca: tunnel) UDP menggunakan alat bernama socat. Alat ini bisa membuat terowongan dua arah (baca: bidirectional) stream byte antara dua titik, baik TCP, UDP, ataupun tun.

Perintah di bawah ini akan membuat antarmuka tun yang di belakangnya jalan proses UDP yang mendengarkan di port 9000. Karena socat dijalankan di kedua tuanrumah, terowongan akan terbentuk. Paket yang datang ke antarmuka tun akan dibungkus UDP dan diteruskan ke antarmuka utama, untuk kemudian dikirimkan ke tujuan tuanrumah.

$ socat TUN:$TUNNEL_IP/16,iff-up UDP:$TO_NODE_IP:9000,bind=$NODE_IP:9000 &$ ip link set dev tun0 mtu 1492

Langkah terakhir. Dalam Linux, jika paket keluar melalui suatu antarmuka, dan paket balasan diterima di antarmuka yang beda, paket akan dijatuhkan. Supaya jaringan overlay terhubung dengan semestinya, kita harus membuat filter jalan terbalik (baca: reverse path filtering) jadi non-aktif.

$ echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
$ echo 0 > /proc/sys/net/ipv4/conf/enp0s8/rp_filter
$ echo 0 > /proc/sys/net/ipv4/conf/br0/rp_filter
$ echo 0 > /proc/sys/net/ipv4/conf/tun0/rp_filter

Kontainer kita sudah siap dites. Mari kita coba koneksi dari kon1 ke kon3.

$ ip netns exec kon1 ping 172.16.1.2

Akhirnya, kita berhasil mengimplementasi jaringan overlay di model ini. Cukup sulit dan rumit, tapi dengan bantuan antarmuka tun, alat socat, dan sedikit penyetelan filter (baca: filter tuning), kita bisa menghubungkan kontainer antar tuanrumah dengan overlay.

Kesimpulan

Cara kerja jaringan kontainer awalnya cukup rumit, tetapi bisa ditelusuri dan dipelajari. Kunci pengertian jaringannya ada pada aturan-aturan rute. Sedangkan, kunci pengertian jaringan overlay ada pada antarmuka tun/tap. Masih ada banyak model jaringan kontainer yang belum sempat dibahas melalui artikel ini. Namun, semua model biasanya membuat setiap kontainer yang tersebar di banyak tuanrumah terhubung dengan alamat IP yang unik.

Referensi

P.S. Jika teman-teman menyukai artikel semacam ini, silakan subscribe ke newsletter kita dan dapatkan notifikasi artikel terbaru langsung di inbox kamu!

--

--

Giri Kuncoro
Pujangga Teknologi

Gojek Engineering. Kubernetes and Containers. Formerly Cornell and VMware/Pivotal in Silicon Valley.