Kubernetes theory
January 21, 2023

Service

Данная сущность кластера k8s обеспечивает доступ к ресурсу в поде извне кластера. Также её можно использовать для доступа к ресурсам пода внутри кластера.

Так для чего же нужна такая сущность как Service, если у пода есть свой адрес и к нему можно обращаться напрямую? Дело в том, что под это сущность не постоянная. Сейчас под есть, а завтра его нет. Завтра вместо этого пода будет другой под с другим адресом. А может не завтра, а через час. И постоянно отслеживать какой адрес сейчас у пода будет неудобно. А если подов не один, а десять? То это рехнуться можно. Вот здесь и появляется сущность Service, которая берёт на себя функцию отслеживания адресов у подов и предоставляет единый интерфейс для доступа к ним.

Существует три типа Service.

1. NodePort. Позволяет обращаться к поду извне кластера k8s с использованием адреса ноды и откытого на ней порта из специального диапазона.
2. ClusterIP. Работает только внутри кластера потому что поддерживает только внутренний ip адрес. Используется по дефолту, если не указан другой тип.
3. LoadBalancer. Данное решение отлично работает в облаке. Форвардит запросы извне на группу бэкендов.

И три типа портов.

1. port. Это порт, который открыт у самого сервиса. Является обязательным параметром.
2. targetPort. Это порт который открыт в контейнере. Если не указан, то используется тот же порт что и в port.
3. nodePort. Используется для доступа к сервису извне. Если не указать, то берётся случайный порт из диапазона 30000-32767

Особенности сервисов.

1. Сервис ищет по лейблам поды, а не деплойменты.
2. Когда поды c определённым лейблом обновляются/добавляются сервис автоматически включает их в правила маршрутизации.
3. Работает на уровне L3.
4. Сервис - это эфемерный объект, представляющий собой набор правил, обеспечивающих взаимодействие подов друг с другом.
5. У сервиса есть тип, селектор по которому ищутся подходящие поды и набор портов к которым открывается доступ.

Для примера работы разных сервисов создадим Deployment с nginx.

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: default
  name: cam-nginx
  labels: 
    app: nginx-prod 
    environment: prod
  annotations:
    author: cameda
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  strategy: 
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports: 
        - containerPort: 80
        resources: 
          requests: 
            cpu: 300m
            memory: 300Mi 
          limits: 
            cpu: 400m 
            memory: 400Mi
      restartPolicy: Always
EOF

Предоставим доступ к поду с помощью Service NodePort:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  namespace: default
  name: nginx-service
  labels:
    environment: prod
  annotations:
    author: cameda
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - name: http
    protocol: TCP
    port: 8080
    targetPort: 80
EOF
kubectl get svc
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
nginx-service   NodePort   10.12.198.238   <none>        8080:32038/TCP   10s

Доступ к поду будет осуществляться с помощью адреса ноды, введённого в браузере и номера nodeport (здесь это 32038). Адрес ноды на которой вертится под можно посмотреть в её дескрайбе.

kubectl describe po cam-nginx-74fdbbbc8d-lrhlq
kubectl describe no cl1n0nosftbqt0s7gocp-ufeg

Этими командами мы смотрим на какой ноде запущен под и какой у ноды внешний адрес. Далее уже с помощью curl проверяем доступность сайта.

curl http://51.250.46.40:32038/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Удалить сервис можно так.

kubectl delete svc nginx-service -n preprod

Откроем доступ по нескольким портам.

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  namespace: default
  name: nginx-service
  labels:
    environment: prod
  annotations:
    author: cameda
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - name: http
    protocol: TCP
    port: 8080
    targetPort: 80
  - name: https
    protocol: TCP
    port: 443
    targetPort: 8070
EOF

Предоставим доступ к поду с помощью Service ClusterIP:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: default
  labels:
    environment: prod
  annotations:
    author: cameda
spec:
  type: ClusterIP
  selector:
    app: nginx
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 31282
EOF

Полезные ссылки.

Вот здесь создавал namespace: https://teletype.in/@cameda2/6tbWe-V5XxZ