Giới thiệu và Thực nghiệm với Network Namespace trong Ảo hóa Mạng Linux

Namespace (không gian tên) và cgroup là hai công nghệ cốt lõi của nhân Linux trong xu hướng container hóa (như Docker). Một cách đơn giản, cgroup là cơ chế giám sát và hạn chế tài nguyên hệ thống thống nhất cho các tiến trình, kiểm soát việc sử dụng tài nguyên hệ thống (CPU, bộ nhớ, etc.). Trong khi đó, namespace là cơ chế đóng gói và cô lập các tài nguyên hệ thống toàn cục, sử dụng các tính năng cô lập và ảo hóa tài nguyên hệ thống của nhân Linux để giới hạn những gì bạn có thể thấy.

Nhân Linux phiên bản 3.8 cung cấp 6 loại namespace: Process ID (pid), Mount (mnt), Network (net), InterProcess Communication (ipc), UTS, và User ID (user). Ví dụ, các tiến trình trong namespace pid chỉ có thể thấy các tiến trình trong cùng namespace đó. Namespace mnt cho phép gắn kết tiến trình vào hệ thống tệp riêng của nó (như chroot). Trong bài viết này, chúng ta sẽ tập trung vào network namespace.

Network namespace cung cấp một ngăn xếp giao thức mạng được cô lập hoàn toàn cho tất cả các tiến trình trong cùng namespace. Điều này bao gồm các giao diện mạng, bảng định tuyến và các quy tắc iptables. Bằng cách sử dụng network namespace, ta có thể tạo ra môi trường mạng ảo hóa, thực hiện sự cô lập mạng lẫn nhau, điều này rất quan trọng cho việc cô lập mạng tenant trong điện toán đám mây. Mạng mạng trong Docker cũng được xây dựng dựa trên cơ chế này.

Chuẩn bị môi trường:

Hệ thống: CentOS 7 (vì namespace được hỗ trợ từ nhân Linux 3.8 trở lên, để thực hiện thí nghiệm này, vui lòng sử dụng phiên bản nhân Linux 3.8 hoặc mới hơn)

Cài đặt iproute (yum install iproute2, với các nền tảng khác vui lòng tải xuống công cụ iproute2)

Lưu ý: Bài viết này sử dụng lệnh ip vì nó đã trở thành công cụ mạng ưu tiên trong Linux, các lệnh cũ như ifconfig, route, etc. đã bị loại bỏ. Lưu ý rằng lệnh ip cần quyền root, do đó các lệnh ip phải được chạy với người dùng root hoặc thêm sudo trước.

1. Tạo một network namespace mới (tên là netns1)

# ip netns add netns0

Giải thích: Về góc độ hệ thống, khi tạo một tiến trình mới thông qua lệnh gọi hệ thống clone(), truyền cờ CLONE_NEWNET sẽ tạo ra một network namespace hoàn toàn mới trong tiến trình đó. Về góc độ người dùng, chúng ta chỉ cần sử dụng công cụ ip (từ gói iproute2) để tạo một network namespace mới: Lệnh này sẽ tạo ra một network namespace mới có tên netns0. Sau khi tạo namespace, lệnh ip sẽ tạo thêm một tệp netns0 trong thư mục /var/run/netns (Trong Linux, Mọi thứ đều là một Tệp).

# ls /var/run/netns
netns0

2. Liệt kê các namespace có sẵn trong hệ thống

# ip netns show
netns0

3. Khởi tạo loopback interface trong namespace

Như đã đề cập, network namespace chứa các tài nguyên mạng riêng: giao diện, bảng định tuyến, etc. Mặc định sau khi thêm network namespace netns1, một giao diện loopback sẽ được tự động thêm vào namespace netns1:

Đầu tiên, kích hoạt giao diện loopback lo:

# ip netns exec netns0 ip link set lo up

Xem thông tin về giao diện loopback lo:

# ip netns exec netns0 ip a
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
  inet6 ::1/128 scope host
      valid_lft forever preferred_lft forever

ping 127.0.0.1
# ip netns exec netns0 ping 127.0.0.1 -c 3
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.016 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.033 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.033 ms

--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.016/0.027/0.033/0.009 ms

4. Tạo kết nối mạng giữa hai namespace

Đã hiểu về network namespace, bây giờ chúng ta sẽ thiết lập kết nối giữa hai namespace cô lập (mô phỏng sự kết nối giữa hai máy chủ, đối với các nhà phát triển mạng đôi khi cần nhiều máy để kiểm tra mạng, nhưng chỉ có một máy, với đặc tính network namespace, hoàn toàn có thể mô phỏng kiểm tra mạng giữa nhiều máy chủ trên cùng một máy vật lý), như sau:

# ip netns add netns1
# ip netns show
netns0
netns1

Để mô phỏng hai máy, chúng ta cần một "cáp mạng" kết nối hai máy chủ, lúc này xuất hiện công cụ veth (virtual ethernet). Veth là một loại thiết bị mạng ảo luôn xuất hiện theo cặp. Bạn có thể xem cặp này như một sợi cáp vật lý, tất cả thứ được gửi từ một đầu sẽ ra ở đầu kia.

Tạo một "cáp mạng" ảo:

# ip link add name cable0 type veth peer name cable1
# ip a
1: cable1@cable0:  mtu 1500 qdisc noop state DOWN group default qlen 1000
  link/ether 52:42:c3:02:54:38 brd ff:ff:ff:ff:ff:ff
2: cable0@cable1:  mtu 1500 qdisc noop state DOWN group default qlen 1000
  link/ether a6:20:57:dc:c6:dd brd ff:ff:ff:ff:ff:ff

Chúng ta có thể thấy đã tạo hai card mạng ảo là cable1@cable0 và cable0@cable1. Bây giờ, hãy cắm một đầu vào máy chủ netns0, đầu còn lại cắm vào máy chủ netns1:

# ip link set cable0 netns netns0
# ip link set cable1 netns netns1

Cấu hình IP cho hai máy chủ tương ứng là 192.168.0.2 và 192.168.0.3, sau đó kiểm tra ping qua lại:

# ip netns exec netns0 ip link set cable0 up
# ip netns exec netns1 ip link set cable1 up
# ip netns exec netns0 ip a add 192.168.0.2 dev cable0
# ip netns exec netns1 ip a add 192.168.0.3 dev cable1
# ip netns exec netns0 ping 192.168.0.3
connect: Mạng không thể truy cập

Mạng không thể truy cập??? Tại sao lại như vậy? Thực ra là vì chưa có định tuyến (xem lệnh định tuyến như sau):

# ip netns exec netns0 ip r

Thêm định tuyến:

# ip netns exec netns0 ip r add 192.168.0.3 dev cable0
# ip netns exec netns1 ip r add 192.168.0.2 dev cable1

Thực hiện ping từ netns0 đến netns1:

# ip netns exec netns0 ping 192.168.0.3 -c 2
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.021 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.047 ms

--- 192.168.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.021/0.034/0.047/0.013 ms

Thẻ: linux network namespace virtualization docker cgroups

Đăng vào ngày 26 tháng 6 lúc 17:44