Работа с Cilium ClusterMesh#
Описание#
Cilium ClusterMesh (ClusterMesh) — это компонент Cilium, предназначенный для объединения нескольких Kubernetes-кластеров в единую сеть. Он позволяет обеспечить прозрачное сетевое взаимодействие между pod, работающими в разных кластерах, а также централизованное управление политиками безопасности и сервисами.
ClusterMesh особенно полезен при работе с географически распределенными системами, где требуется высокая доступность, отказоустойчивость и единая логика маршрутизации.
Контекст использования#
Объединение кластеров#
ClusterMesh позволяет нескольким Kubernetes-кластерам работать как единая система. Pod из одного кластера может напрямую взаимодействовать с pod из другого кластера, организуя единое сетевое пространство.
Например, кластеры расположены в Москве, Минске и Астане. С помощью ClusterMesh можно организовать прозрачную связь между ними, независимо от их физического местонахождения.
Global Services#
ClusterMesh поддерживает создание глобальных сервисов (сервис с аннотациями service.cilium.io/global: "true" и service.cilium.io/global-sync-endpoint-slices: "true"), которые балансируют трафик между экземплярами одного и того же сервиса в разных кластерах.
Описание работы:
Микросервис
ordersзапущен в каждом кластере.Через глобальный параметр
Serviceзапросы равномерно распределяются между кластерами.При отключении одного кластера нагрузка автоматически перераспределяется на оставшиеся.
Например, в случае разработки интернет-магазина с кластерами, размещенными в регионах Европа, США, Cilium ClusterMesh позволяет:
Реплицировать данные между кластерами.
Сделать сервис
paymentsдоступным из любого кластера.Обеспечить отказоустойчивость, при которой в случае выхода из строя одного кластера второй берет на себя его нагрузку.
Централизованное управление#
С помощью ClusterMesh можно применять сетевые политики (NetworkPolicy) ко всем кластерам сразу, что упрощает управление безопасностью и маршрутизацией.
Возможности сетевой политики:
Единое пространство имен для всех кластеров.
Поддержка DNS-запросов между кластерами.
Возможность управления через Kubectl из одного места.
Безопасность#
Все соединения между кластерами шифруются с использованием mTLS (mutual TLS, mutual Transport Layer Security) . Это гарантирует, что только доверенные кластеры могут обмениваться данными и передавать информацию безопасно.
Конфигурация DropAppConfiguration для объединения кластеров в одну сеть#
Для проверки работы ClusterMesh воспользуйтесь сценарием создания трех кластеров DropApp с помощью Dactl и объедения их в один кластер.
Генерация общего набора сертификатов TLS#
Чтобы clustermesh-apiserver мог корректно использовать mTLS, необходимо сгенерировать единый набор сертификатов, которые будут использоваться в каждом кластере.
Создайте файл конфигурации
cilium-ca.confс информацией о корневом сертификате:cilium-ca.conf
[req] distinguished_name = req_distinguished_name prompt = no x509_extensions = ca_x509_extensions [ca_x509_extensions] basicConstraints = CA:TRUE keyUsage = cRLSign, keyCertSign [req_distinguished_name] CN = Cilium C = RU ST = Moscow L = Moscow [clustermesh-server] distinguished_name = clustermesh-server_distinguished_name prompt = no req_extensions = clustermesh-server_req_extensions [clustermesh-server_req_extensions] basicConstraints = CA:FALSE extendedKeyUsage = clientAuth, serverAuth keyUsage = critical, digitalSignature, keyEncipherment nsCertType = client nsComment = "Clustermesh Server Certificate" subjectAltName = @clustermesh-server_alt_names subjectKeyIdentifier = hash [clustermesh-server_distinguished_name] C = RU ST = Moscow L = Moscow [clustermesh-server_alt_names] IP.0 = <clustermesh-ip> DNS.0 = clustermesh-apiserver.cilium.io DNS.1 = *.mesh.cilium.io DNS.2 = localhost DNS.3 = clustermesh-apiserver.kube-system.svc.cluster.local DNS.4 = clustermesh-apiserver.kube-system DNS.5 = clustermesh-apiserver DNS.6 = clustermesh-apiserver.kube-system.svc # Clustermesh Admin Cert [clustermesh-admin] distinguished_name = clustermesh-admin_distinguished_name prompt = no req_extensions = clustermesh-admin_req_extensions [clustermesh-admin_req_extensions] basicConstraints = CA:FALSE extendedKeyUsage = clientAuth, serverAuth keyUsage = critical, digitalSignature, keyEncipherment nsCertType = client nsComment = "Clustermesh Admin Certificate" subjectAltName = @clustermesh-admin_alt_names subjectKeyIdentifier = hash [clustermesh-admin_distinguished_name] CN = root O = Cilium C = RU ST = Moscow L = Moscow [clustermesh-admin_alt_names] IP.0 = <clustermesh-ip> DNS.0 = localhost DNS.1 = clustermesh-apiserver.kube-system.svc.cluster.local DNS.2 = clustermesh-apiserver.kube-system DNS.3 = clustermesh-apiserver DNS.4 = clustermesh-apiserver.kube-system.svc # Clustermesh Client Cert [clustermesh-client] distinguished_name = clustermesh-client_distinguished_name prompt = no req_extensions = clustermesh-client_req_extensions [clustermesh-client_req_extensions] basicConstraints = CA:FALSE extendedKeyUsage = clientAuth, serverAuth keyUsage = critical, digitalSignature, keyEncipherment nsCertType = client nsComment = "Clustermesh Client Certificate" subjectKeyIdentifier = hash [clustermesh-client_distinguished_name] CN = remote O = Cilium C = RU ST = Moscow L = Moscow [clustermesh-client_alt_names] IP.0 = <clustermesh-ip> DNS.0 = localhost DNS.1 = clustermesh-apiserver.kube-system.svc.cluster.local DNS.2 = clustermesh-apiserver.kube-system DNS.3 = clustermesh-apiserver DNS.4 = clustermesh-apiserver.kube-system.svcСоздайте скрипт
generate-cilium-certs.sh:generate-cilium-certs.sh
#!/bin/bash set -e OUTPUT_DIR="cilium-cluster-certs" rm -rf "$OUTPUT_DIR" mkdir -p "$OUTPUT_DIR" echo "### Генерация корневого CA" openssl genrsa -out "$OUTPUT_DIR/ca.key" 4096 openssl req -x509 -new -sha512 -noenc \ -key "$OUTPUT_DIR/ca.key" -days 3653 \ -config cilium-ca.conf \ -out "$OUTPUT_DIR/ca.crt" echo "### Генерация server admin client" certs=( "clustermesh-server" "clustermesh-admin" "clustermesh-client" ) for i in ${certs[*]}; do openssl genrsa -out "$OUTPUT_DIR/${i}.key" 4096 openssl req -new -key "$OUTPUT_DIR/${i}.key" -sha256 \ -config "cilium-ca.conf" -section ${i} \ -out "$OUTPUT_DIR/${i}.csr" openssl x509 -req -days 3653 -in "$OUTPUT_DIR/${i}.csr" \ -copy_extensions copyall \ -sha256 -CA "$OUTPUT_DIR/ca.crt" \ -CAkey "$OUTPUT_DIR/ca.key" \ -CAcreateserial \ -out "$OUTPUT_DIR/${i}.crt" cat "$OUTPUT_DIR/${i}.crt" | base64 | tr -d '\n' > "$OUTPUT_DIR/${i}.crt.b64" cat "$OUTPUT_DIR/${i}.key" | base64 | tr -d '\n' > "$OUTPUT_DIR/${i}.key.b64" done # --- Сохраняем корневой ca.crt тоже в base64 --- cat "$OUTPUT_DIR/ca.crt" | base64 | tr -d '\n' > "$OUTPUT_DIR/ca.crt.b64" cat "$OUTPUT_DIR/ca.key" | base64 | tr -d '\n' > "$OUTPUT_DIR/ca.key.b64" # --- Сохраняем все данные в values.yaml --- cat > "values.yaml" <<EOF tls: ca: cert: $(cat "$OUTPUT_DIR/ca.crt.b64") key: $(cat "$OUTPUT_DIR/ca.key.b64") clustermesh: useAPIServer: true apiserver: tls: auto: enabled: false server: cert: $(cat "$OUTPUT_DIR/clustermesh-server.crt.b64") key: $(cat "$OUTPUT_DIR/clustermesh-server.key.b64") admin: cert: $(cat "$OUTPUT_DIR/clustermesh-admin.crt.b64") key: $(cat "$OUTPUT_DIR/clustermesh-admin.key.b64") client: cert: $(cat "$OUTPUT_DIR/clustermesh-client.crt.b64") key: $(cat "$OUTPUT_DIR/clustermesh-client.key.b64") remote: cert: $(cat "$OUTPUT_DIR/clustermesh-client.crt.b64") key: $(cat "$OUTPUT_DIR/clustermesh-client.key.b64") EOF echo "✅ Все сертификаты готовы в папке: $OUTPUT_DIR" echo "👉 Используйте содержимое файла: ./values.yaml"Сделайте файл исполняемым:
chmod +x ./generate-cilium-certs.shЗапустите скрипт:
sudo ./generate-cilium-certs.sh
Скрипт создаст сертификаты и values.yaml, содержимое которого необходимо добавить в DropAppConfiguration для каждого кластера.
Создание кластеров DropApp#
Создайте 3 кластера DropApp, например, c именами: cluster-rio, cluster-bravo, cluster-marco.
Для того чтобы визуально наблюдать общую сеть кластеров, необходимо настроить ClusterMesh и включить Hubble-ui.
Предварительные требования к кластерам#
Предварительными требованиями являются:
Кластеры должны иметь:
разный
cilium.cluster.idи разныйcilium.cluster.name;один общий набор сертификатов;
разный, не пересекающийся
podSubnetCIDR.
Сервис для
clustermesh-apiserverдолжен иметь типLoadBalancerи для него Metallb должен выделить пул из двух адресов (один для сервисаclustermesh-apiserver, второй - для сервисаingress-nginx-controller).Все узлы всех кластеров должны иметь сетевую связность. Если они географически распределены, то должен быть VPN или иной способ туннелирования между сетями кластеров.
Кластер cluster-rio#
Пример конфигурации da-cluster-rio.yaml:
da-cluster-rio.yaml
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: cluster-rio
spec:
skipComponentsInstall: false
network:
publicDomain: dapp.test.un.sbt
metallb:
pools:
- addresses: "<rio-cluster-pool-ip>"
name: "dapp"
l2Advertisement: true
hostAliases:
- hostnames:
- console.cluster-rio.dapp.test.un.sbt
- auth.cluster-rio.dapp.test.un.sbt
- alertmanager.cluster-rio.dapp.test.un.sbt
- metrics.cluster-rio.dapp.test.un.sbt
ip: <rio-cluster-ip2>
artifacts:
imageRegistry:
host: <host>
path: <path>
credentials: <image-cred>
compute:
sshAccess:
user: dapp
privateKeyPath: "~/.ssh/id_k8s"
userProvisioned:
nodes:
controlPlane:
- ip: "<rio-control-plane-ip>"
nodePool: "control-plane"
worker:
- ip: "<rio-worker1-ip>"
nodePool: "worker"
- ip: "<rio-worker2-ip>"
nodePool: "worker"
k8s:
podSubnetCIDR: <rio-podSubnetCIDR-ip>
serviceSubnetCIDR: <serviceSubnetCIDR-ip>
cni:
cilium:
values:
cluster:
name: cluster-rio
id: 1
hubble:
enabled: true
ui:
enabled: true
relay:
enabled: true
tls:
ca:
cert: <rio-tls-cert>
key: <rio-tls-key>
clustermesh:
useAPIServer: true
apiserver:
tls:
auto:
enabled: false
server:
cert: <rio-clustermesh-tls-server-cert>
key: <rio-clustermesh-tls-server-key>
admin:
cert: <rio-clustermesh-tls-admin-cert>
key: <rio-clustermesh-tls-admin-key>
client:
cert: <rio-clustermesh-tls-client-cert>
key: <rio-clustermesh-tls-client-key>
remote:
cert: <rio-clustermesh-tls-remote-cert>
key: <rio-clustermesh-tls-remote-key>
service:
type: LoadBalancer
loadBalancerIP: <rio-cluster-ip1>
replicas: 1
config:
enabled: true
clusters:
- name: cluster-rio
port: 2379
ips:
- <rio-cluster-ip1>
- name: cluster-bravo
port: 2379
ips:
- <bravo-cluster-ip1>
- name: cluster-marco
port: 2379
ips:
- <marco-cluster-ip1>
Кластер cluster-bravo#
Пример конфигурации da-cluster-bravo.yaml:
da-cluster-bravo.yaml
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: cluster-bravo
spec:
skipComponentsInstall: false
network:
publicDomain: dapp.test.un.sbt
metallb:
pools:
- addresses: "<bravo-cluster-pool-ip>"
name: "dapp"
l2Advertisement: true
hostAliases:
- hostnames:
- console.cluster-bravo.dapp.test.un.sbt
- auth.cluster-bravo.dapp.test.un.sbt
- alertmanager.cluster-bravo.dapp.test.un.sbt
- metrics.cluster-bravo.dapp.test.un.sbt
ip: <bravo-cluster-ip2>
artifacts:
imageRegistry:
host: <host>
path: <path>
credentials: <image-cred>
compute:
sshAccess:
user: dapp
privateKeyPath: "~/.ssh/id_k8s"
userProvisioned:
nodes:
controlPlane:
- ip: "<bravo-control-plane-ip>"
nodePool: "control-plane"
worker:
- ip: "<bravo-worker1-ip>"
nodePool: "worker"
- ip: "<bravo-worker2-ip>"
nodePool: "worker"
k8s:
podSubnetCIDR: <rio-podSubnetCIDR-ip>
serviceSubnetCIDR: <serviceSubnetCIDR-ip>
cni:
cilium:
values:
cluster:
name: cluster-bravo
id: 2
hubble:
enabled: true
ui:
enabled: true
relay:
enabled: true
tls:
ca:
cert: <bravo-tls-cert>
key: <bravo-tls-key>
clustermesh:
useAPIServer: true
apiserver:
tls:
auto:
enabled: false
server:
cert: <bravo-clustermesh-tls-server-cert>
key: <bravo-clustermesh-tls-server-key>
admin:
cert: <bravo-clustermesh-tls-admin-cert>
key: <bravo-clustermesh-tls-admin-key>
client:
cert: <bravo-clustermesh-tls-client-cert>
key: <bravo-clustermesh-tls-client-key>
remote:
cert: <bravo-clustermesh-tls-remote-cert>
key: <bravo-clustermesh-tls-remote-key>
service:
type: LoadBalancer
loadBalancerIP: <bravo-cluster-ip1>
replicas: 1
config:
enabled: true
clusters:
- name: cluster-rio
port: 2379
ips:
- <rio-cluster-ip1>
- name: cluster-bravo
port: 2379
ips:
- <bravo-cluster-ip1>
- name: cluster-marco
port: 2379
ips:
- <marco-cluster-ip1>
Кластер cluster-marco#
Пример конфигурации da-cluster-marco.yaml:
da-cluster-marco.yaml
apiVersion: config.dropapp.ru/v1alpha1
kind: DropAppConfiguration
metadata:
name: cluster-marco
spec:
skipComponentsInstall: false
network:
publicDomain: dapp.test.un.sbt
metallb:
pools:
- addresses: "<bravo-cluster-pool-ip>"
name: "dapp"
l2Advertisement: true
hostAliases:
- hostnames:
- console.cluster-marco.dapp.test.un.sbt
- auth.cluster-marco.dapp.test.un.sbt
- alertmanager.cluster-marco.dapp.test.un.sbt
- metrics.cluster-marco.dapp.test.un.sbt
ip: <marco-cluster-ip2>
artifacts:
imageRegistry:
host: <host>
path: <path>
credentials: <image-cred>
compute:
sshAccess:
user: dapp
privateKeyPath: "~/.ssh/id_k8s"
userProvisioned:
nodes:
controlPlane:
- ip: "<marco-control-plane-ip>"
nodePool: "control-plane"
worker:
- ip: "<marco-worker1-ip>"
nodePool: "worker"
- ip: "<marco-worker2-ip>"
nodePool: "worker"
k8s:
podSubnetCIDR: <rio-podSubnetCIDR-ip>
serviceSubnetCIDR: <serviceSubnetCIDR-ip>
cni:
cilium:
values:
cluster:
name: cluster-marco
id: 3
hubble:
enabled: true
ui:
enabled: true
relay:
enabled: true
tls:
ca:
cert: <marco-tls-cert>
key: <marco-tls-key>
clustermesh:
useAPIServer: true
apiserver:
tls:
auto:
enabled: false
server:
cert: <marco-clustermesh-tls-server-cert>
key: <marco-clustermesh-tls-server-key>
admin:
cert: <marco-clustermesh-tls-admin-cert>
key: <marco-clustermesh-tls-admin-key>
client:
cert: <marco-clustermesh-tls-client-cert>
key: <marco-clustermesh-tls-client-key>
remote:
cert: <marco-clustermesh-tls-remote-cert>
key: <marco-clustermesh-tls-remote-key>
service:
type: LoadBalancer
loadBalancerIP: <marco-cluster-ip1>
replicas: 1
config:
enabled: true
clusters:
- name: cluster-rio
port: 2379
ips:
- <rio-cluster-ip1>
- name: cluster-bravo
port: 2379
ips:
- <bravo-cluster-ip1>
- name: cluster-marco
port: 2379
ips:
- <marco-cluster-ip1>
Запуск Dactl#
Запустите создание кластеров:
dactl create cluster --config ./da-cluster-rio.yaml
dactl create cluster --config ./da-cluster-bravo.yaml
dactl create cluster --config ./da-cluster-marco.yaml
Проверка ClusterMesh#
Проверка стабильности состояния общей сети#
Для проверки стабильности состояния сети между кластерами в Cilium выполните шаги:
Скачайте бинарный файл Cilium:
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt) GOOS=$(go env GOOS) GOARCH=$(go env GOARCH) curl -L --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-${GOOS}-${GOARCH}.tar.gz{,.sha256sum} sha256sum --check cilium-${GOOS}-${GOARCH}.tar.gz.sha256sum sudo tar -C /usr/local/bin -xzvf cilium-${GOOS}-${GOARCH}.tar.gz rm cilium-${GOOS}-${GOARCH}.tar.gz{,.sha256sum}Проверьте статус кластера
cluster-rio:./cilium-clustermesh/cilium clustermesh status --kubeconfig ~/.dropapp/cluster-rio/kubeconfig --waitПример вывода:
✅ Service "clustermesh-apiserver" of type "LoadBalancer" found ✅ Cluster access information is available: - <bravo-cluster-ip1>:2379 ✅ Deployment clustermesh-apiserver is ready ℹ️ KVStoreMesh is enabled ... ⌛ Waiting (2m36s) for clusters to be connected: 3 nodes are not ready ... ⌛ Waiting (3m48s) for clusters to be connected: 1 nodes are not ready ✅ All 3 nodes are connected to all clusters [min:2 / avg:2.0 / max:2] ✅ All 1 KVStoreMesh replicas are connected to all clusters [min:2 / avg:2.0 / max:2] 🔌 Cluster Connections: - cluster-marco: 3/3 configured, 3/3 connected - KVStoreMesh: 1/1 configured, 1/1 connected - cluster-bravo: 3/3 configured, 3/3 connected - KVStoreMesh: 1/1 configured, 1/1 connected 🔀 Global services: [ min:0 / avg:0.0 / max:0 ]Повторите команду для каждого из оставшихся кластеров:
./cilium-clustermesh/cilium clustermesh status --kubeconfig ~/.dropapp/cluster-bravo/kubeconfig --wait./cilium-clustermesh/cilium clustermesh status --kubeconfig ~/.dropapp/cluster-marco/kubeconfig --waitВывод команд должен быть аналогичным
cluster-rio.
Тест ClusterMesh#
Создайте манифест
test-rio.yamlдляcluster-rio:test-rio.yaml
--- apiVersion: apps/v1 kind: Deployment metadata: name: rebel-base spec: selector: matchLabels: name: rebel-base replicas: 2 template: metadata: labels: name: rebel-base spec: containers: - name: rebel-base image: docker.io/nginx:1.27.1 volumeMounts: - name: html mountPath: /usr/share/nginx/html/ livenessProbe: httpGet: path: / port: 80 periodSeconds: 1 readinessProbe: httpGet: path: / port: 80 volumes: - name: html configMap: name: rebel-base-response items: - key: message path: index.html --- apiVersion: v1 kind: ConfigMap metadata: name: rebel-base-response data: message: "{\"Galaxy\": \"Rio\", \"Cluster\": \"cluster-rio\"}\n" --- apiVersion: apps/v1 kind: Deployment metadata: name: x-wing spec: selector: matchLabels: name: x-wing replicas: 2 template: metadata: labels: name: x-wing spec: containers: - name: x-wing-container image: quay.io/cilium/json-mock:v1.3.8@sha256:<cilium-sha> livenessProbe: exec: command: - curl - -sS - -o - /dev/null - localhost readinessProbe: exec: command: - curl - -sS - -o - /dev/null - localhost --- apiVersion: v1 kind: Service metadata: name: rebel-base annotations: service.cilium.io/global: "true" spec: type: ClusterIP ports: - port: 80 selector: name: rebel-base --- apiVersion: v1 kind: Service metadata: name: rebel-base-headless annotations: service.cilium.io/global: "true" service.cilium.io/global-sync-endpoint-slices: "true" spec: type: ClusterIP clusterIP: None ports: - port: 80 selector: name: rebel-baseПримените манифест:
kubectl apply -f ./test-rio.yaml --kubeconfig ~/.dropapp/cluster-rio/kubeconfigСоздайте манифест
test-bravo.yamlдляcluster-bravo:test-bravo.yaml
--- apiVersion: apps/v1 kind: Deployment metadata: name: rebel-base spec: selector: matchLabels: name: rebel-base replicas: 2 template: metadata: labels: name: rebel-base spec: containers: - name: rebel-base image: docker.io/nginx:1.27.1 volumeMounts: - name: html mountPath: /usr/share/nginx/html/ livenessProbe: httpGet: path: / port: 80 periodSeconds: 1 readinessProbe: httpGet: path: / port: 80 volumes: - name: html configMap: name: rebel-base-response items: - key: message path: index.html --- apiVersion: v1 kind: ConfigMap metadata: name: rebel-base-response data: message: "{\"Galaxy\": \"Bravo\", \"Cluster\": \"cluster-bravo\"}\n" --- apiVersion: apps/v1 kind: Deployment metadata: name: x-wing spec: selector: matchLabels: name: x-wing replicas: 2 template: metadata: labels: name: x-wing spec: containers: - name: x-wing-container image: quay.io/cilium/json-mock:v1.3.8@sha256:<cilium-sha> livenessProbe: exec: command: - curl - -sS - -o - /dev/null - localhost readinessProbe: exec: command: - curl - -sS - -o - /dev/null - localhost --- apiVersion: v1 kind: Service metadata: name: rebel-base annotations: service.cilium.io/global: "true" spec: type: ClusterIP ports: - port: 80 selector: name: rebel-base --- apiVersion: v1 kind: Service metadata: name: rebel-base-headless annotations: service.cilium.io/global: "true" service.cilium.io/global-sync-endpoint-slices: "true" spec: type: ClusterIP clusterIP: None ports: - port: 80 selector: name: rebel-baseПримените манифест:
kubectl apply -f ./test-bravo.yaml --kubeconfig ~/.dropapp/cluster-bravo/kubeconfigСоздайте манифест
test-marco.yamlдляcluster-marco:test-marco.yaml
--- apiVersion: apps/v1 kind: Deployment metadata: name: rebel-base spec: selector: matchLabels: name: rebel-base replicas: 2 template: metadata: labels: name: rebel-base spec: containers: - name: rebel-base image: docker.io/nginx:1.27.1 volumeMounts: - name: html mountPath: /usr/share/nginx/html/ livenessProbe: httpGet: path: / port: 80 periodSeconds: 1 readinessProbe: httpGet: path: / port: 80 volumes: - name: html configMap: name: rebel-base-response items: - key: message path: index.html --- apiVersion: v1 kind: ConfigMap metadata: name: rebel-base-response data: message: "{\"Galaxy\": \"Marco\", \"Cluster\": \"cluster-marco\"}\n" --- apiVersion: apps/v1 kind: Deployment metadata: name: x-wing spec: selector: matchLabels: name: x-wing replicas: 2 template: metadata: labels: name: x-wing spec: containers: - name: x-wing-container image: quay.io/cilium/json-mock:v1.3.8@sha256:<cilium-sha> livenessProbe: exec: command: - curl - -sS - -o - /dev/null - localhost readinessProbe: exec: command: - curl - -sS - -o - /dev/null - localhost --- apiVersion: v1 kind: Service metadata: name: rebel-base annotations: service.cilium.io/global: "true" spec: type: ClusterIP ports: - port: 80 selector: name: rebel-base --- apiVersion: v1 kind: Service metadata: name: rebel-base-headless annotations: service.cilium.io/global: "true" service.cilium.io/global-sync-endpoint-slices: "true" spec: type: ClusterIP clusterIP: None ports: - port: 80 selector: name: rebel-baseПримените манифест:
kubectl apply -f ./test-marco.yaml --kubeconfig ~/.dropapp/cluster-marco/kubeconfigДля проверки работоспособности ClusterMesh, на любом кластере, например,
cluster-rio, запустите pod (netshoot), который будет слать запросы в «свой» сервисrebel-base:kubectl --kubeconfig ~/.dropapp/cluster-rio/kubeconfig run --restart Never --rm -it --image nicolaka/netshoot netshoot -- /bin/sh -c 'for i in $$(seq 1 100); do curl http://rebel-base/; done'В примере вывода ответы идут из разных кластеров:
Пример вывода
{"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Rio", "Cluster": "cluster-rio"} {"Galaxy": "Marco", "Cluster": "cluster-marco"} {"Galaxy": "Bravo", "Cluster": "cluster-bravo"} pod "netshoot" deletedClusterMesh работает.
Убедитесь, что в Hubble-ui данные о пакетах учитывают все 3 кластера:
