Как развернуть сервис в Kubernetes: гайд для начинающих

от автора

Привет, Хабр! Сегодня мы попробуем развернуть простой сервис в Kubernetes на примере KaaS в облачной платформе Рег.ру. В качестве самого сервиса будем использовать imgproxy — минималистичный сервис подготовки изображений для web с предельно простым API. 

Этот гайд будет полезен новичкам, которые только начинают работу с Kubernetes. Рассмотрим, как настраивать среду и управлять ей, и освоим принципы работы с контейнерами. Кроме того, развертывание imgproxy в качестве примера поможет научиться обрабатывать изображения с помощью Kubernetes простым и удобным способом.

Навигация по тексту:

Создание кластера Kubernetes
Получение kubeconfig
Проверка kubeconfig
Установка ingress-nginx
Установка cert-manager
Разворачиваем imgproxy
Проверка работоспособности

Создание кластера Kubernetes

Для начала нам нужно создать кластер Kubernetes в личном кабинете облака cloud.reg.ru, например, с тремя воркер-нодами:

Получение kubeconfig

После создания кластера, чтобы к нему подключиться через kubectl, нужно получить для него файл kubeconfig со страницы деталей:

Подсказка: если это ваш единственный кластер Kubernetes, вы можете переместить файл kubeconfig в место по умолчанию: ~/.kube/config и не использовать далее параметр —kubeconfig. Для этого достаточно выполнить в терминале:

→ mv -v <путь к скачанному файлу> ~/.kube/config

В случае, если кластер не единственный и/или управление контекстами в kubectl кажется неудобным, можно использовать разные файлы kubeconfig для разных окружений. Такой способ может быть безопаснее в некоторых случаях: например, если некоторые файлы kubeconfig находятся на внешних зашифрованных носителях.

Проверка kubeconfig

После получения файла kubeconfig нужно проверить его работоспособность. Запросим список нод, неймспейсов, подов:

→ kubectl --kubeconfig ~/Downloads/kubeconfig_4137209 get nodes NAME                             STATUS   ROLES    AGE   VERSION k8s4137209-az1-md1-gb86x-6fbhz   Ready    <none>   24m   v1.30.2 k8s4137209-az1-md1-gb86x-cxxwq   Ready    <none>   24m   v1.30.2 k8s4137209-az1-md1-gb86x-pkvvk   Ready    <none>   24m   v1.30.2
→ kubectl --kubeconfig ~/Downloads/kubeconfig_4137209 get namespaces NAME              STATUS   AGE default           Active   26m kube-node-lease   Active   26m kube-public       Active   26m kube-system       Active   26m
→ kubectl --kubeconfig ~/Downloads/kubeconfig_4137209 get pods -A NAMESPACE     NAME                               READY   STATUS    RESTARTS   AGE kube-system   cilium-99rxc                       1/1     Running   0          24m kube-system   cilium-envoy-72sxw                 1/1     Running   0          25m kube-system   cilium-envoy-88bcm                 1/1     Running   0          24m kube-system   cilium-envoy-xk7t7                 1/1     Running   0          24m kube-system   cilium-gfb8h                       1/1     Running   0          25m kube-system   cilium-l4q2c                       1/1     Running   0          24m kube-system   cilium-operator-5cb45868f8-n55fq   1/1     Running   0          25m kube-system   coredns-68d4f9776f-l2sbw           1/1     Running   0          25m kube-system   coredns-68d4f9776f-xjwm7           1/1     Running   0          25m kube-system   konnectivity-agent-4924v           1/1     Running   0          24m kube-system   konnectivity-agent-gmgvb           1/1     Running   0          24m kube-system   konnectivity-agent-v4f2l           1/1     Running   0          24m

Похоже, что все компоненты на месте, ноды есть. kube-apiserver, отдающий нам эту информацию, тоже работает.

Установка ingress-nginx

Начнем с установки ingress controller’а. Он нужен нам для того, чтобы получить трафик внутрь кластера Kubernetes. Использовать ingress’ы — не единственный способ этого достичь, но зачастую самый простой и удобный. В качестве ingress контроллера мы будем использовать ingress-nginx и дополним его cert-manager’ом для обеспечения возможности выписывания TLS-сертификатов от Let’s Encrypt.

Для установки ingress-nginx проще всего использовать helm:

→ helm \    --kubeconfig ~/Downloads/kubeconfig_4137209 \    upgrade \        --install ingress-nginx ingress-nginx/ingress-nginx \        --namespace ingress-nginx \        --create-namespace \ --set controller.kind=DaemonSet

Затем смотрим список подов и сервисов в namespace’е ingress-nginx и убеждаемся, что под с ingress controller’ом запущен, сервис создан и ему выделен внешний IP-адрес:

→ kubectl --kubeconfig ~/Downloads/kubeconfig_4137209 get pods,svc -n ingress-nginx NAME                                           READY   STATUS    RESTARTS   AGE pod/ingress-nginx-controller-55dd9c5f4-bv2mc   1/1     Running   0          92s   NAME                                         TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                      AGE service/ingress-nginx-controller             LoadBalancer   10.105.18.179   89.108.100.213   80:31362/TCP,443:32472/TCP   92s service/ingress-nginx-controller-admission   ClusterIP      10.102.26.77    <none>           443/TCP                      92s

Установка cert-manager

cert-manager устанавливается по аналогии:

→ helm \    --kubeconfig ~/Downloads/kubeconfig_4137209 \    upgrade \        --install cert-manager jetstack/cert-manager \        --namespace cert-manager \        --create-namespace \        --set crds.enabled=true

Если по какой-то причине эта операция завершится ошибкой, в этом нет ничего страшного. Нужно просто повторить команду.

Единственное отличие: нам нужно будет создать ClusterIssuer для использования Let’s Encrypt, который мы возьмем прямо из документации cert-manager:

--- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata:  name: letsencrypt-prod spec:  acme:    # The ACME server URL    server: https://acme-v02.api.letsencrypt.org/directory    # Email address used for ACME registration    email: user@example.com    # Name of a secret used to store the ACME account private key    privateKeySecretRef:      name: letsencrypt-prod    # Enable the HTTP-01 challenge provider    solvers:      - http01:          ingress:            ingressClassName: nginx

Сохраним в файл и выполним kubectl apply на него:

→ cat <<EOF > clusterissuer.yaml --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata:  name: letsencrypt-prod spec:  acme:    # The ACME server URL    server: https://acme-v02.api.letsencrypt.org/directory    # Email address used for ACME registration    email: user@example.com    # Name of a secret used to store the ACME account private key    privateKeySecretRef:      name: letsencrypt-prod    # Enable the HTTP-01 challenge provider    solvers:      - http01:          ingress:            ingressClassName: nginx EOF   → kubectl --kubeconfig ~/Downloads/kubeconfig_4137209 apply -f clusterissuer.yaml

Теперь нам нужно определиться с доменным именем, на котором будет работать наше тестовое приложение imgproxy. Я выберу поддомен imgproxy к одному из своих доменов и добавлю для него A-запись в DNS со значением внешнего IP сервиса — 89.108.100.213 в примере выше (у вас будет свой IP-адрес, ну и поддомен вы также можете выбрать свой).

Разворачиваем imgproxy

На этом инфраструктурная часть фактически закончена, и мы можем развернуть imgproxy. Он уже собран и поставляется в виде образа контейнера, для него даже есть готовый Helm Chart. Сам imgproxy в своей конфигурации очень прост, и в данном случае хочется показать “подкапотное пространство”, потому егомы развернем вручную, т.е. с использованием описаний самого Kubernetes. Для этого нам потребуется создать три ресурса: Deployment — с самим с приложением, Service — для организации балансировки между несколькими инстансами imgproxy и Ingress — для обеспечения доступа из сети Интернет. Бонусом, т.к. мы настроили cert-manager, мы получим TLS для нашего imgproxy.

Создаем deployment.yaml:

→ cat <<EOF > deployment.yaml --- apiVersion: apps/v1 kind: Deployment metadata:  name: imgproxy  labels:    app.kubernetes.io/name: imgproxy    app.kubernetes.io/app: imgproxy spec:  replicas: 3  strategy:    type: RollingUpdate  revisionHistoryLimit: 3  selector:    matchLabels:      app.kubernetes.io/name: imgproxy      app.kubernetes.io/app: imgproxy  template:    metadata:      labels:        app.kubernetes.io/name: imgproxy        app.kubernetes.io/app: imgproxy    spec:      affinity:        podAntiAffinity:          requiredDuringSchedulingIgnoredDuringExecution:          - labelSelector:              matchExpressions:              - key: app.kubernetes.io/app                operator: In                values:                - imgproxy            topologyKey: "kubernetes.io/hostname"      terminationGracePeriodSeconds: 30      automountServiceAccountToken: false      containers:        - name: imgproxy          image: darthsim/imgproxy:latest          imagePullPolicy: IfNotPresent          env:              # the maximum duration (in seconds) for processing the response.              # Default: 10            - name: IMGPROXY_WRITE_TIMEOUT              value: '30'              # the maximum duration (in seconds) to wait for the next request              # before closing the connection. When set to 0, keep-alive is              # disabled. Default: 10            - name: IMGPROXY_KEEP_ALIVE_TIMEOUT              value: '30'              # the maximum duration (in seconds) to wait for the next request              # before closing the HTTP client connection. The HTTP client is              # used to download source images. When set to 0, keep-alive is              # disabled. Default: 90            - name: IMGPROXY_CLIENT_KEEP_ALIVE_TIMEOUT              value: '40'              # the maximum duration (in seconds) for downloading the source              # image. Default: 5            - name: IMGPROXY_DOWNLOAD_TIMEOUT              value: '30'              # when set to true, enables using the ETag HTTP header for HTTP              # cache control. Default: false            - name: IMGPROXY_USE_ETAG              value: 'true'              # when set to true, enables using the Last-Modified HTTP header              # for HTTP cache control. Default: false            - name: IMGPROXY_USE_LAST_MODIFIED              value: 'true'              # when set to true, imgproxy will add debug headers to the response.              # Default: false. The following headers will be added:              #              # X-Origin-Content-Length: the size of the source image              # X-Origin-Width: the width of the source image              # X-Origin-Height: the height of the source image              # X-Result-Width: the width of the resultant image              # X-Result-Height: the height of the resultant image            - name: IMGPROXY_ENABLE_DEBUG_HEADERS              value: 'true'              # the maximum resolution of the source image, in megapixels.              # Images with larger actual size will be rejected. Default: 50            - name: IMGPROXY_MAX_SRC_RESOLUTION              value: '70'              # the maximum size of the source image, in bytes. Images with              # larger file size will be rejected. When set to 0, file size              # check is disabled. Default: 0            - name: IMGPROXY_MAX_SRC_FILE_SIZE              value: '104857600'              # the default quality of the resultant image, percentage.              # Default: 80            - name: IMGPROXY_QUALITY              value: '90'              # default quality of the resulting image per format, separated              # by commas. Example: jpeg=70,avif=40,webp=60. When a value for              # the resulting format is not set, the IMGPROXY_QUALITY value is              # used. Default: avif=65            - name: IMGPROXY_FORMAT_QUALITY              value: 'jpeg=90'          ports:            - name: http              containerPort: 8080              protocol: TCP          resources:            requests:              cpu: 10m              memory: 32Mi            limits:              memory: 1Gi          securityContext:            allowPrivilegeEscalation: false            readOnlyRootFilesystem: true EOF 

service.yaml:

→ cat <<EOF > service.yaml --- apiVersion: v1 kind: Service metadata:  name: imgproxy  labels:    app.kubernetes.io/name: imgproxy    app.kubernetes.io/app: imgproxy spec:  ports:  - name: http    port: 8080    protocol: TCP    targetPort: 8080  selector:    app.kubernetes.io/name: imgproxy    app.kubernetes.io/app: imgproxy  type: ClusterIP EOF

В ingress.yaml нужно поменять название домена на свой собственный, для которого была добавлена A-запись:

→ cat <<EOF > ingress.yaml --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata:  annotations:    ingress.kubernetes.io/ssl-redirect: "true"    nginx.ingress.kubernetes.io/ssl-redirect: "true"    kubernetes.io/ingress.class: nginx    kubernetes.io/tls-acme: "true"    cert-manager.io/cluster-issuer: letsencrypt-prod    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"    nginx.ingress.kubernetes.io/client-body-buffer-size: 256m    nginx.ingress.kubernetes.io/proxy-body-size: 256m  labels:    app.kubernetes.io/name: imgproxy    app.kubernetes.io/app: imgproxy  name: imgproxy spec:  ingressClassName: nginx  rules:  - host: imgproxy.my-domain.ru    http:      paths:      - backend:          service:            name: imgproxy            port:              number: 8080        path: /        pathType: Prefix  tls:  - hosts:    - imgproxy.my-domain.ru    secretName: imgproxy.my-domain.ru EOF

Примечание: в примере выше используется доменное имя imgproxy.my-domain.ru, его нужно заменить на свое собственное.

После создания файлов применяем изменения:

kubectl apply -f deployment.yaml -f service.yaml -f ingress.yaml

Проверка работоспособности

Открываем браузер и идем по адресу https://<наш домен>/unsafe/resize:fit:300:300/plain/https:%2F%2Fmars.nasa.gov%2Fsystem%2Fdownloadable_items%2F40368_PIA22228.jpg

В результате мы видим изображение с размером, вписанным в квадрат 300×300 пикселей, т.е. все работает.

Мы пошагово разобрали, как развернуть сервис imgproxy в Kubernetes с помощью KaaS в облаке Рег.ру. Теперь, когда сервис работает, можно смело настраивать его, масштабировать и оптимизировать для своих задач. Если вы хотите углубиться в тему Kubernetes, прочитайте наши предыдущие статьи. Ранее мы писали про архитектуру KaaS и рассказывали о том, как мы его запускали в облаке Рег.ру.


ссылка на оригинал статьи https://habr.com/ru/articles/856686/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *