#13 DevOps. Kubernetes. Ingress Controllers

Ingress Controller можно сравнить с консьержем в многоквартирном доме, где квартиры — это ваши приложения, к которым вы хотите получить доступ извне.

Когда кто-то из интернета хочет получить доступ к вашему приложению, запрос сначала поступает на Ingress Controller, а он уже перенаправляет его по адресу. 

Рассмотрим на практике.

Создадим виртуальную машину на Ubuntu 22.04 LTS, установим Docker и сделаем Snapshot (он пригодится нам для следующих примеров). 

Теперь установим minikube

curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64

sudo install minikube-linux-amd64 /usr/local/bin/minikube && rm minikube-linux-amd64

sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

sudo docker run hello-world

minikube config set driver docker

sudo usermod -aG docker $USER && newgrp docker

minikube start

Подождем, установим kubectl и проверим

curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"

sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

kubectl version --client

kubectl get po -A

Теперь рассмотрим пример с Ingress Controller

Установим Ingress в наш minikube кластер

minikube addons enable ingress

Подождем и проверим

kubectl get pods -n ingress-nginx

Сделаем так, чтобы запрос на myapplication.ru/v1 был перенаправлен на версию приложения 1.0, а на myapplication.ru/v2 соответственно на версию 2.0.

В /etc/hosts добавим наш домен myapplication.ru и резолв на свой ip адрес 

nano applications.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: appv1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: v1
  template:
    metadata:
      labels:
        app: v1
    spec:
      containers:
      - name: appv1
        image: gcr.io/google-samples/hello-app:1.0

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: appv2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: v2
  template:
    metadata:
      labels:
        app: v2
    spec:
      containers:
      - name: appv2
        image: gcr.io/google-samples/hello-app:2.0

---
apiVersion: v1
kind: Service
metadata:
  name: appv1-service
  labels:
    app: v1
spec:
  ports:
    - port: 8080
      nodePort: 30005
  type: NodePort
  selector:
    app: v1

---
apiVersion: v1
kind: Service
metadata:
  name: appv2-service
  labels:
    app: v2
spec:
  ports:
    - port: 8080
      nodePort: 30006
  type: NodePort
  selector:
    app: v2

Я выбрал NodePort, а не ClusterIP просто для примера, у нас не прод.

Запустим и проверим

kubectl apply -f applications.yaml

kubectl get pods

kubectl get services

Создадим наш Ingress

nano ingress.yaml

apiVersion: networking.k8s.io/v1   
kind: Ingress   
metadata:   
  name: appingress  
  annotations:   
    nginx.ingress.kubernetes.io/rewrite-target: /$1   
spec:   
  rules:   
    - host: myapplication.ru  
      http:   
        paths:   
          - path: /v1  
            pathType: Prefix   
            backend:   
              service:   
                name: appv1-service
                port:   
                  number: 8080
          - path: /v2
            pathType: Prefix   
            backend:   
              service:   
                name: appv2-service
                port:   
                  number: 8080

Запустим и проверим

kubectl apply -f ingress.yaml

kubectl get ingress

Теперь проверим

testvm:~$ curl http://myapplication.ru/v1
Hello, world!
Version: 1.0.0
Hostname: appv1-5d7fb68ff5-bd49l

testvm:~$ curl http://myapplication.ru/v2
Hello, world!
Version: 2.0.0
Hostname: appv2-69cb58d76b-fdwl2

Как видим все работает

Теперь остановим запущенные ресурсы или откатимся к нашему snapshot и рассмотрим другой пример

kubectl delete -f applications.yaml

kubectl delete -f ingress.yaml

Остановим minikube

minikube stop

Установим kind

[ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.23.0/kind-linux-amd64

chmod +x ./kind

sudo mv ./kind /usr/local/bin/kind

Запустим кластер

nano kind-config.yaml

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
  extraPortMappings:
  - containerPort: 80
    hostPort: 80
    listenAddress: "0.0.0.0"  
  - containerPort: 443
    hostPort: 443
    listenAddress: "0.0.0.0"

kind create cluster --config kind-config.yaml

Проверим

kubectl get nodes

Далее установим и проверим Contour

kubectl apply -f https://projectcontour.io/quickstart/contour.yaml

kubectl get pods -n projectcontour -o wide

Установим httpbin и проверим

kubectl apply -f https://projectcontour.io/examples/httpbin.yaml

kubectl get po,svc,ing -l app=httpbin

Сделаем port-forward с локальной машины на Envoy

kubectl -n projectcontour port-forward service/envoy 8888:80 

В моей случае виртуалка запущена в Яндекс Облако, поэтому добавим опцию —address чтобы проверить доступ из интернета

kubectl -n projectcontour port-forward service/envoy 8888:80 --address 0.0.0.0

В браузере открываем http://158.160.109.6:8888 (у вас будет свой ip) и видим страницу httpbin.org

Далее остановим httpbin и удалим кластер

kubectl delete -f https://projectcontour.io/examples/httpbin.yaml

kind delete cluster

kind get clusters

Рассмотрим последний пример

cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  kubeadmConfigPatches:
  - |
    kind: InitConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        node-labels: "ingress-ready=true"
  extraPortMappings:
  - containerPort: 80
    hostPort: 80
    protocol: TCP
  - containerPort: 443
    hostPort: 443
    protocol: TCP
EOF

kubectl get nodes

kind get clusters

Далее выполним

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

Проверим

kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=90s

Запустим

kubectl apply -f https://kind.sigs.k8s.io/examples/ingress/usage.yaml

Проверим

curl localhost/foo/hostname

curl localhost/bar/hostname

В ответ видим

foo-app
bar-app

Мы рассмотрели очень простые примеры как локально, так и в облаке, но для базового понимания работы Ingress они вполне подходят.