Container, microservice và lưới dịch vụ

Trên mạng một bó Điều о lưới dịch vụ (lưới dịch vụ) và đây là một cái khác. Hoan hô! Nhưng tại sao? Sau đó, tôi muốn nêu quan điểm của mình rằng các lưới dịch vụ sẽ tốt hơn 10 năm trước, trước khi các nền tảng vùng chứa như Docker và Kubernetes ra đời. Tôi không nói rằng quan điểm của tôi tốt hơn hay tệ hơn những quan điểm khác, nhưng vì lưới dịch vụ là động vật khá phức tạp, nên nhiều quan điểm sẽ giúp hiểu rõ hơn về chúng.

Tôi sẽ nói về nền tảng dotCloud, được xây dựng trên hơn một trăm vi dịch vụ và hỗ trợ hàng nghìn ứng dụng trong vùng chứa. Tôi sẽ giải thích những thách thức mà chúng tôi gặp phải khi phát triển và khởi chạy nó cũng như cách lưới dịch vụ có thể (hoặc có thể không) trợ giúp.

lịch sử dotcloud

Tôi đã viết về lịch sử của dotCloud và sự lựa chọn kiến ​​trúc cho nền tảng này, nhưng chưa nói nhiều về lớp mạng. Nếu bạn không muốn đọc bài báo cuối cùng về dotCloud, đây là ý chính của nó: đó là một dịch vụ nền tảng PaaS cho phép khách hàng chạy nhiều loại ứng dụng (Java, PHP, Python...), với sự hỗ trợ cho nhiều loại dịch vụ dữ liệu ( MongoDB, MySQL, Redis...) và quy trình công việc như Heroku: bạn tải mã của mình lên nền tảng, nền tảng này xây dựng hình ảnh bộ chứa và triển khai chúng.

Tôi sẽ cho bạn biết lưu lượng truy cập đã được gửi đến nền tảng dotCloud như thế nào. Không phải vì nó đặc biệt hay (mặc dù hệ thống hoạt động tốt vào thời điểm đó!), mà chủ yếu là vì với sự trợ giúp của các công cụ hiện đại, một thiết kế như vậy có thể dễ dàng được thực hiện trong thời gian ngắn bởi một nhóm khiêm tốn nếu họ cần một cách định tuyến lưu lượng truy cập giữa một loạt các vi dịch vụ hoặc một loạt các ứng dụng. Do đó, bạn có thể so sánh các tùy chọn: điều gì sẽ xảy ra nếu bạn tự phát triển mọi thứ hoặc sử dụng lưới dịch vụ hiện có. Lựa chọn tiêu chuẩn: tự làm hoặc mua.

Định tuyến lưu lượng cho các ứng dụng được lưu trữ

Các ứng dụng trên dotCloud có thể hiển thị các điểm cuối HTTP và TCP.

điểm cuối HTTP được thêm động vào cấu hình cụm cân bằng tải hà mã. Điều này tương tự như những gì tài nguyên đang làm ngày nay Sự đi vào trong Kubernetes và bộ cân bằng tải như traefik.

Máy khách kết nối với các điểm cuối HTTP thông qua các miền thích hợp, miễn là tên miền trỏ tới bộ cân bằng tải dotCloud. Không có gì đặc biệt.

điểm cuối TCP được liên kết với một số cổng, sau đó được chuyển đến tất cả các vùng chứa trong ngăn xếp đó thông qua các biến môi trường.

Khách hàng có thể kết nối với các điểm cuối TCP bằng tên máy chủ thích hợp (chẳng hạn như gateway-X.dotcloud.com) và số cổng.

Tên máy chủ này phân giải thành cụm máy chủ "nats" (không liên quan đến NAT) sẽ định tuyến các kết nối TCP đến đến đúng bộ chứa (hoặc, trong trường hợp dịch vụ cân bằng tải, đến đúng bộ chứa).

Nếu bạn đã quen thuộc với Kubernetes, điều này có thể sẽ khiến bạn nhớ đến các dịch vụ Cổng nút.

Không có dịch vụ tương đương trên nền tảng dotCloud Cụm IP: để đơn giản, việc truy cập vào các dịch vụ diễn ra theo cùng một cách cả từ bên trong và bên ngoài nền tảng.

Mọi thứ được tổ chức khá đơn giản: việc triển khai ban đầu các mạng định tuyến HTTP và TCP có lẽ chỉ là vài trăm dòng Python. Các thuật toán đơn giản (tôi muốn nói là ngây thơ) đã được tinh chỉnh cùng với sự phát triển của nền tảng và sự xuất hiện của các yêu cầu bổ sung.

Không cần tái cấu trúc rộng rãi mã hiện có. Đặc biệt, Ứng dụng 12 yếu tố có thể trực tiếp sử dụng địa chỉ thu được thông qua các biến môi trường.

Điều này khác với lưới dịch vụ hiện đại như thế nào?

Giới hạn hiển thị. Chúng tôi không có bất kỳ số liệu nào cho lưới định tuyến TCP. Khi nói đến định tuyến HTTP, các phiên bản gần đây hơn có các chỉ số HTTP chi tiết với mã lỗi và thời gian phản hồi, nhưng lưới dịch vụ hiện đại còn đi xa hơn nữa, cung cấp khả năng tích hợp với các hệ thống thu thập chỉ số như Prometheus chẳng hạn.

Khả năng hiển thị không chỉ quan trọng từ quan điểm vận hành (để giúp khắc phục sự cố) mà còn khi các tính năng mới được phát hành. Nói về an toàn triển khai xanh lam и triển khai chim hoàng yến.

định tuyến hiệu quả cũng bị hạn chế. Trong lưới định tuyến dotCloud, tất cả lưu lượng truy cập phải đi qua một cụm các nút định tuyến chuyên dụng. Điều này có nghĩa là có khả năng vượt qua nhiều ranh giới AZ (vùng khả dụng) và độ trễ tăng đáng kể. Tôi nhớ mã khắc phục sự cố đã thực hiện hơn một trăm truy vấn SQL trên mỗi trang và mở một kết nối mới tới máy chủ SQL cho mỗi truy vấn. Khi chạy cục bộ, trang tải ngay lập tức, nhưng trên dotCloud phải mất vài giây để tải vì mỗi kết nối TCP (và truy vấn SQL tiếp theo) mất hàng chục mili giây. Trong trường hợp cụ thể này, các kết nối liên tục đã giải quyết được vấn đề.

Các lưới dịch vụ hiện đại xử lý tốt hơn các vấn đề như vậy. Trước hết, họ kiểm tra xem các kết nối đã được định tuyến chưa trong nguồn. Luồng logic là như nhau: клиент → меш → сервис, nhưng bây giờ lưới hoạt động cục bộ chứ không phải trên các nút từ xa, vì vậy kết nối клиент → меш là cục bộ và rất nhanh (micro giây thay vì mili giây).

Các lưới dịch vụ hiện đại cũng triển khai các thuật toán cân bằng tải thông minh hơn. Bằng cách theo dõi tình trạng của các chương trình phụ trợ, họ có thể gửi nhiều lưu lượng truy cập hơn đến các chương trình phụ trợ nhanh hơn, dẫn đến hiệu suất tổng thể tốt hơn.

Безопасность cũng tốt hơn. Lưới định tuyến dotCloud chạy hoàn toàn trên EC2 Classic và không mã hóa lưu lượng (với giả định rằng nếu ai đó quản lý để đưa trình nghe lén vào lưu lượng mạng EC2, thì bạn đã gặp rắc rối lớn rồi). Ví dụ: lưới dịch vụ hiện đại bảo vệ minh bạch tất cả lưu lượng truy cập của chúng tôi bằng xác thực TLS lẫn nhau và mã hóa tiếp theo.

Định tuyến lưu lượng cho các dịch vụ nền tảng

Được rồi, chúng ta đã thảo luận về lưu lượng giữa các ứng dụng, nhưng còn nền tảng dotCloud thì sao?

Bản thân nền tảng này bao gồm khoảng một trăm dịch vụ siêu nhỏ chịu trách nhiệm cho các chức năng khác nhau. Một số đang chấp nhận yêu cầu từ những người khác và một số là nhân viên chạy ngầm kết nối với các dịch vụ khác nhưng bản thân họ không chấp nhận kết nối. Trong cả hai trường hợp, mỗi dịch vụ phải biết điểm cuối của các địa chỉ mà nó cần kết nối.

Nhiều dịch vụ cấp cao có thể sử dụng lưới định tuyến được mô tả ở trên. Trên thực tế, nhiều trong số hơn XNUMX vi dịch vụ dotCloud đã được triển khai dưới dạng các ứng dụng thông thường trên chính nền tảng dotCloud. Nhưng một số ít dịch vụ cấp thấp (đặc biệt là những dịch vụ triển khai mạng lưới định tuyến này) cần thứ gì đó đơn giản hơn, ít phụ thuộc hơn (vì chúng không thể tự hoạt động - vấn đề gà và trứng cũ).

Các dịch vụ thiết yếu, cấp thấp này đã được triển khai bằng cách chạy các vùng chứa trực tiếp trên một vài nút chính. Đồng thời, các dịch vụ nền tảng tiêu chuẩn không được tham gia: trình liên kết, trình lập lịch trình và trình chạy. Nếu bạn muốn so sánh với các nền tảng container hiện đại, nó giống như khởi chạy một chiếc máy bay điều khiển với docker run trực tiếp trên các nút, thay vì ủy thác nhiệm vụ cho Kubernetes. Nó khá giống nhau trong khái niệm mô-đun tĩnh (nhóm), sử dụng kubeadm hoặc bootkube khi khởi động một cụm độc lập.

Các dịch vụ này được hiển thị một cách đơn giản và thô thiển: một tệp YAML liệt kê tên và địa chỉ của chúng; và mỗi khách hàng phải lấy một bản sao của tệp YAML này để triển khai.

Một mặt, điều này cực kỳ đáng tin cậy vì nó không yêu cầu sự hỗ trợ của kho lưu trữ khóa/giá trị bên ngoài, chẳng hạn như Zookeeper (hãy nhớ rằng, etcd hoặc Consul không tồn tại vào thời điểm đó). Mặt khác, nó gây khó khăn cho việc di chuyển các dịch vụ. Mỗi lần di chuyển được thực hiện, tất cả khách hàng phải nhận tệp YAML được cập nhật (và có khả năng tải lại). Không thoải mái lắm!

Sau đó, chúng tôi bắt đầu triển khai một sơ đồ mới, trong đó mỗi máy khách được kết nối với một máy chủ proxy cục bộ. Thay vì địa chỉ và cổng, nó chỉ cần biết số cổng của dịch vụ và kết nối qua localhost. Proxy cục bộ xử lý kết nối này và chuyển tiếp nó đến máy chủ thực tế. Giờ đây, khi di chuyển phần phụ trợ sang máy khác hoặc mở rộng quy mô, thay vì cập nhật tất cả máy khách, chỉ cần cập nhật tất cả các proxy cục bộ này; và khởi động lại không còn cần thiết.

(Nó cũng được lên kế hoạch đóng gói lưu lượng truy cập trong các kết nối TLS và cài đặt một máy chủ proxy khác ở bên nhận, cũng như kiểm tra các chứng chỉ TLS mà không có sự tham gia của dịch vụ nhận, được định cấu hình để chỉ chấp nhận các kết nối trên localhost. Thêm về điều đó sau).

Điều này rất giống với ngăn xếp thông minh từ Airbnb, nhưng sự khác biệt đáng kể là SmartStack được triển khai và triển khai vào sản xuất, trong khi hệ thống định tuyến nội bộ của dotCloud đã được đóng hộp khi dotCloud chuyển thành Docker.

Cá nhân tôi coi SmartStack là một trong những tiền thân của các hệ thống như Istio, Linkerd và Consul Connect vì tất cả chúng đều theo cùng một khuôn mẫu:

  • Chạy một proxy trên mỗi nút.
  • Khách hàng kết nối với proxy.
  • Mặt phẳng điều khiển cập nhật cấu hình proxy khi phụ trợ thay đổi.
  • … Lợi nhuận!

Triển khai lưới dịch vụ hiện đại

Nếu chúng ta cần triển khai một lưới tương tự ngày nay, chúng ta có thể sử dụng các nguyên tắc tương tự. Ví dụ: thiết lập vùng DNS nội bộ bằng cách ánh xạ tên dịch vụ tới địa chỉ trong không gian 127.0.0.0/8. Sau đó chạy HAProxy trên mỗi nút cụm, chấp nhận các kết nối trên từng địa chỉ dịch vụ (trên mạng con đó 127.0.0.0/8) và chuyển hướng/cân bằng tải sang các chương trình phụ trợ thích hợp. Cấu hình HAProxy có thể được quản lý tâm sự, cho phép bạn lưu trữ thông tin phụ trợ trong etcd hoặc Consul và tự động đẩy cấu hình cập nhật lên HAProxy khi cần.

Đây gần như là cách Istio hoạt động! Nhưng với một số khác biệt:

  • Sử dụng Đại sứ ủy nhiệm thay vì HAProxy.
  • Lưu cấu hình phụ trợ thông qua Kubernetes API thay vì etcd hoặc Consul.
  • Các dịch vụ được phân bổ địa chỉ trên mạng con nội bộ (địa chỉ Kubernetes ClusterIP) thay vì 127.0.0.0/8.
  • Có một thành phần bổ sung (Citadel) để thêm xác thực TLS lẫn nhau giữa máy khách và máy chủ.
  • Hỗ trợ các tính năng mới như ngắt mạch, theo dõi phân tán, triển khai canary, v.v.

Chúng ta hãy xem nhanh một số khác biệt.

Đại sứ ủy nhiệm

Envoy Proxy được viết bởi Lyft [Đối thủ cạnh tranh của Uber trên thị trường taxi - xấp xỉ. mỗi.]. Nó tương tự theo nhiều cách với các proxy khác (ví dụ: HAProxy, Nginx, Traefik...), nhưng Lyft đã viết riêng vì họ cần các tính năng mà các proxy khác không có và việc tạo một cái mới thay vì mở rộng có vẻ hợp lý hơn một cái hiện có.

Envoy có thể được sử dụng bởi chính nó. Nếu tôi có một dịch vụ cụ thể cần kết nối với các dịch vụ khác, tôi có thể thiết lập dịch vụ đó để kết nối với Envoy, sau đó tự động định cấu hình và định cấu hình lại Envoy với vị trí của các dịch vụ khác, đồng thời nhận được nhiều tính năng bổ sung tuyệt vời như khả năng hiển thị. Thay vì một thư viện ứng dụng khách tùy chỉnh hoặc đưa vào mã theo dõi cuộc gọi, chúng tôi gửi lưu lượng truy cập đến Envoy và Envoy thu thập số liệu cho chúng tôi.

Nhưng Envoy cũng có thể làm việc như mặt phẳng dữ liệu (mặt phẳng dữ liệu) cho lưới dịch vụ. Điều này có nghĩa là bây giờ đối với lưới dịch vụ này, Envoy được định cấu hình máy bay điều khiển (máy bay điều khiển).

máy bay điều khiển

Trong mặt phẳng điều khiển, Istio dựa vào Kubernetes API. Điều này không khác lắm so với việc sử dụng confd, dựa vào etcd hoặc Consul để tra cứu một bộ khóa trong kho dữ liệu. Istio xem xét một tập hợp các tài nguyên Kubernetes thông qua API Kubernetes.

Giữa điều này và sau đó: Cá nhân tôi thấy điều này hữu ích Mô tả về API Kubernetesmà đọc:

Máy chủ API Kubernetes là một "máy chủ ngu ngốc" cung cấp lưu trữ, tạo phiên bản, xác thực, cập nhật và ngữ nghĩa tài nguyên API.

Istio được thiết kế để hoạt động với Kubernetes; và nếu bạn muốn sử dụng nó bên ngoài Kubernetes, thì bạn cần bắt đầu một phiên bản của máy chủ API Kubernetes (và dịch vụ trợ giúp etcd).

Địa chỉ dịch vụ

Istio dựa vào các địa chỉ ClusterIP mà Kubernetes phân bổ, vì vậy các dịch vụ Istio nhận địa chỉ nội bộ (không nằm trong phạm vi 127.0.0.0/8).

Lưu lượng truy cập đến một địa chỉ ClusterIP cho một dịch vụ cụ thể trong cụm Kubernetes không có Istio bị chặn bởi kube-proxy và được gửi đến chương trình phụ trợ của proxy. Nếu bạn quan tâm đến các chi tiết kỹ thuật, kube-proxy sẽ thiết lập quy tắc iptables (hoặc bộ cân bằng tải IPVS, tùy thuộc vào cách nó được định cấu hình) để ghi lại địa chỉ IP đích của các kết nối đi đến địa chỉ ClusterIP.

Khi Istio được cài đặt trên cụm Kubernetes, sẽ không có gì thay đổi cho đến khi nó được kích hoạt rõ ràng cho một người tiêu dùng nhất định hoặc thậm chí toàn bộ không gian tên bằng cách giới thiệu một vùng chứa sidecar vào nhóm tùy chỉnh. Vùng chứa này sẽ tạo ra một phiên bản của Envoy và thiết lập một bộ quy tắc iptables để chặn lưu lượng truy cập đến các dịch vụ khác và chuyển hướng lưu lượng truy cập đó đến Envoy.

Khi được tích hợp với Kubernetes DNS, điều này có nghĩa là mã của chúng tôi có thể kết nối theo tên dịch vụ và mọi thứ “chỉ hoạt động”. Nói cách khác, mã của chúng tôi đưa ra các truy vấn như http://api/v1/users/4242sau đó api giải quyết yêu cầu cho 10.97.105.48, các quy tắc iptables sẽ chặn các kết nối từ 10.97.105.48 và chuyển hướng chúng đến proxy Envoy cục bộ, proxy này sẽ chuyển tiếp yêu cầu đến phần phụ trợ API thực tế. Phù!

rườm rà bổ sung

Istio cũng cung cấp mã hóa đầu cuối và xác thực thông qua mTLS (TLS tương hỗ). Thành phần được gọi là Citadel.

Ngoài ra còn có một thành phần Mixer, mà Envoy có thể yêu cầu cho môi yêu cầu đưa ra quyết định đặc biệt về yêu cầu đó tùy thuộc vào nhiều yếu tố khác nhau như tiêu đề, tải phụ trợ, v.v... (đừng lo lắng: có nhiều công cụ giúp Trình trộn hoạt động và ngay cả khi nó gặp sự cố, Envoy vẫn tiếp tục hoạt động làm đại diện).

Và, tất nhiên, chúng tôi đã đề cập đến khả năng hiển thị: Envoy thu thập một lượng lớn số liệu trong khi cung cấp theo dõi phân tán. Trong kiến ​​trúc vi dịch vụ, nếu một yêu cầu API duy nhất cần đi qua các vi dịch vụ A, B, C và D, thì khi đăng nhập, tính năng theo dõi phân tán sẽ thêm một mã định danh duy nhất vào yêu cầu và lưu trữ mã định danh này thông qua các yêu cầu phụ cho tất cả các dịch vụ siêu nhỏ này, cho phép bạn để nắm bắt tất cả các cuộc gọi liên quan, độ trễ của chúng, v.v.

Phát triển hoặc mua

Istio nổi tiếng là một hệ thống phức tạp. Ngược lại, việc xây dựng mạng lưới định tuyến mà tôi đã mô tả ở đầu bài viết này tương đối dễ dàng với các công cụ hiện có. Vì vậy, thay vào đó, việc tạo lưới dịch vụ của riêng bạn có hợp lý không?

Nếu chúng tôi có nhu cầu khiêm tốn (chúng tôi không cần khả năng hiển thị, bộ ngắt mạch và những thứ tinh tế khác), thì chúng tôi sẽ nghĩ đến việc phát triển công cụ của riêng mình. Nhưng nếu chúng ta đang sử dụng Kubernetes, điều đó thậm chí có thể không cần thiết vì Kubernetes đã cung cấp các công cụ cơ bản để khám phá dịch vụ và cân bằng tải.

Nhưng nếu chúng tôi có các yêu cầu nâng cao, thì "mua" lưới dịch vụ có vẻ là một lựa chọn tốt hơn nhiều. (Đây không phải lúc nào cũng là "mua hàng" vì Istio là mã nguồn mở, nhưng chúng tôi vẫn cần đầu tư thời gian kỹ thuật để hiểu, triển khai và quản lý nó.)

Chọn gì: Istio, Linkerd hoặc Consul Connect?

Cho đến nay chúng ta mới chỉ nói về Istio, nhưng nó không phải là lưới dịch vụ duy nhất. Sự thay thế phổ biến là liên kết, nhưng có nhiều hơn Kết nối lãnh sự.

Những gì để lựa chọn?

Thành thật mà nói, tôi không biết. Hiện tại tôi không cho rằng mình đủ thẩm quyền để trả lời câu hỏi này. Có một vài thú vị Điều với sự so sánh của các công cụ này và thậm chí điểm chuẩn.

Một cách tiếp cận đầy hứa hẹn là sử dụng một công cụ như siêu bóng. Nó triển khai một lớp trừu tượng để đơn giản hóa và thống nhất các API do lưới dịch vụ cung cấp. Thay vì tìm hiểu các API cụ thể (và theo ý kiến ​​của tôi là tương đối phức tạp) của các mắt lưới dịch vụ khác nhau, chúng ta có thể sử dụng các cấu trúc SuperGloo đơn giản hơn - và dễ dàng chuyển từ cái này sang cái khác, như thể chúng ta có một định dạng cấu hình trung gian mô tả các giao diện và phụ trợ HTTP có khả năng tạo cấu hình thực tế cho Nginx, HAProxy, Traefik, Apache…

Tôi đã tìm hiểu một chút về Istio và SuperGloo, và trong bài viết tiếp theo, tôi muốn trình bày cách thêm Istio hoặc Linkerd vào một cụm hiện có bằng cách sử dụng SuperGloo và cách thức sau này sẽ thực hiện công việc của nó, nghĩa là nó cho phép bạn chuyển từ lưới dịch vụ này sang dịch vụ khác mà không cần viết lại cấu hình.

Nguồn: www.habr.com

Thêm một lời nhận xét