iptables в контейнере инициализации kuberntes не работает

#kubernetes #reverse-proxy #iptables #istio

#kubernetes #обратный прокси #iptables #istio

Вопрос:

Предыстория:

Я пытаюсь использовать goreplay для зеркального отображения трафика в другое место назначения. Я обнаружил, что служба k8s — это балансировка нагрузки на уровне 4, из-за чего трафик не может быть перехвачен goreplay, поэтому я решаю добавить вспомогательный модуль обратного прокси внутри pod, как это делает istio.

Вот мой модуль yaml:

 apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: nginx
    ports:
    - containerPort: 80
      name: http
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: proxy
    resources:
      limits:
        cpu: "2"
        memory: 1Gi
      requests:
        cpu: 10m
        memory: 40Mi
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File  
    volumeMounts:
      - mountPath: /etc/nginx/conf.d
        name: default   
  initContainers:
    - command: 
      - iptables
      args:
      - -t 
      - nat
      - -A
      - PREROUTING
      - -p
      - tcp
      - --dport
      - "80"
      - -j
      - REDIRECT
      - --to-ports
      - "15001"
      image: soarinferret/iptablesproxy
      imagePullPolicy: IfNotPresent
      name: istio-init
      resources:
        limits:
          cpu: 100m
          memory: 50Mi
        requests:
          cpu: 10m
          memory: 10Mi
      securityContext:
        allowPrivilegeEscalation: false
        capabilities:
          add:
          - NET_ADMIN
          - NET_RAW
          drop:
          - ALL
        privileged: false
        readOnlyRootFilesystem: false
        runAsGroup: 0
        runAsNonRoot: false
        runAsUser: 0
      terminationMessagePath: /dev/termination-log
      terminationMessagePolicy: File        
  dnsPolicy: ClusterFirst
  terminationGracePeriodSeconds: 30
  volumes:
    - configMap:
        defaultMode: 256
        name: default
        optional: false
      name: default
---

apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: default
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

--- 

apiVersion: v1
data:
  default.conf: |
    server {
        listen       15001;
        server_name  localhost;
        access_log  /var/log/nginx/host.access.log  main;
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }
kind: ConfigMap
metadata:
  name: default
  namespace: default
  

Я использую, kubectl port-forward service/nginx 8080:80 а затем curl http://localhost:8080 трафик был отправлен непосредственно на nginx, а не на мой прокси.

ЧЕГО я ХОЧУ:

  1. Способ позволить goreplay захватывать трафик, который балансируется службой k8s.
  2. Исправьте правило iptables, чтобы трафик успешно направлялся на мой прокси-сервер.

Спасибо за любую помощь!

Комментарии:

1. просто отправьте порт трафика 15001 в определении вашего сервиса.

2. Не могли бы вы попробовать с iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 80 -j REDIRECT --to-port 15001 ? Кроме того, я бы посоветовал ознакомиться с этим руководством по этому поводу, не совсем по nginx, но объясняет, как на самом деле создать прокси.

3. Если вы скопировали часть контейнера инициализации из istio: 15001 для исходящего трафика, 15006 для входящего трафика. Входящая часть отсутствует.

4. @Jakub Большое спасибо за ваш ответ, после того, как я поработал с руководством, которое вы даете, я обнаружил, что перенаправление портов отличается от обычного вызова службы k8s. После того, как я изменил привилегированное значение на ture в поле SecurityContext initConatiner, все работает хорошо.

5. @Jonyhy96 Конечно, рад, что это работает для вас! Я добавил ответ для большей наглядности. Если бы это помогло рассмотреть возможность голосования / принятия ответа.

Ответ №1:

Как упоминал @Jonyhy96 в комментариях, единственное, что здесь нужно изменить, — это присвоить привилегированному значению значение true в SecurityContext поле initContainer.

Привилегированный — определяет, может ли какой-либо контейнер в модуле включать привилегированный режим. По умолчанию контейнеру не разрешен доступ к каким-либо устройствам на хосте, но «привилегированному» контейнеру предоставляется доступ ко всем устройствам на хосте. Это обеспечивает контейнеру почти тот же доступ, что и процессам, запущенным на хосте. Это полезно для контейнеров, которые хотят использовать возможности Linux, такие как управление сетевым стеком и доступ к устройствам.


Таким образом, initContainer будет выглядеть следующим образом

 initContainers:
    - command: 
      - iptables
      args:
      - -t 
      - nat
      - -A
      - PREROUTING
      - -p
      - tcp
      - --dport
      - "80"
      - -j
      - REDIRECT
      - --to-ports
      - "15001"
      image: soarinferret/iptablesproxy
      imagePullPolicy: IfNotPresent
      name: istio-init
      resources:
        limits:
          cpu: 100m
          memory: 50Mi
        requests:
          cpu: 10m
          memory: 10Mi
      securityContext:
        allowPrivilegeEscalation: false
        capabilities:
          add:
          - NET_ADMIN
          - NET_RAW
          drop:
          - ALL
        privileged: true   <---- changed from false
        readOnlyRootFilesystem: false
        runAsGroup: 0
        runAsNonRoot: false
        runAsUser: 0
      terminationMessagePath: /dev/termination-log
      terminationMessagePolicy: File 
  

Об этом есть очень хороший учебник, не совсем по nginx, но объясняет, как на самом деле создать прокси.

Ответ №2:

Приведенный выше SecurityContext работает, за исключением требования изменения для разрешения расширения привилегий: true

Следующая урезанная версия также работает на GKE (движок Google Kubernetes):

     securityContext:
      capabilities:
        add:
        - NET_ADMIN
        drop:
        - ALL
      privileged: true