Архив метки: Devops

Проксирование внешнего веб-сайта с помощью Nginx Ingress

Представьте, что у вас есть веб-сервер, работающий вне вашего кластера Kubernetes, который вы хотите интегрировать в свой контроллер ingress. Существует несколько причин, по которым вы можете захотеть это сделать:




  • Внешний веб-сервер разработан не таким образом, чтобы вы могли (легко) запустить его в контейнере вашего кластера.



  • Возможно, внешний веб-сервер запущен в другом центре обработки данных, чем ваш кластер Kubernetes.



  • Вы хотите воспользоваться преимуществами автоматической настройки HTTPS вашего контроллера Nginx Ingress.




Оказывается, на самом деле это довольно просто настроить.




В этом примере мы предполагаем, что внешний веб-сайт размещен на IP-адресе 10.20.30.40 и прослушивается через порт 8080. Обратите внимание, что для этого примера мы предполагаем, что порт 8080 обслуживает незашифрованный простой HTTP.




Также убедитесь, что вы правильно настроили свой брандмауэр и ограничили IP-адрес, по которому этот веб-сервер принимает подключения. Вы же не хотите открывать незашифрованный порт 8080 для всего мира.




Прежде всего, вам необходимо создать сервис с конечной точкой:




service.yaml




apiVersion: v1
kind: Service
metadata:
  name: <my-external-service>
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  clusterIP: None
  type: ClusterIP
---
apiVersion: v1
kind: Endpoints
metadata:
  name: <my-external-service>
subsets:
- addresses:
  - ip: 10.20.30.40
  ports:
  - name: http
    port: 8080
    protocol: TCP




По сути, мы сообщаем Kubernetes, что определяем службу, которая связана с внешним IP-адресом, прослушивающим определенный порт. Мы используем IP-адрес, чтобы избежать DNS-запросов, задействованных в этой настройке.




Загрузка его в кластер выполняется следующим образом:




$ kubectl apply -f service.yaml




Для завершения настройки мы добавляем сервис в определение ingress точно так же, как мы бы поступили с обычным сервисом:




ingress.yaml




apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress
  annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    kubernetes.io/ingress.class: nginx
    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - <my-domain-name.com>
    secretName: letsencrypt-prod
  rules:
  - host: <my-domain-name.com>
    http:
      paths:
      - backend:
          serviceName: <my-external-service>
          servicePort: 80




Примените это также, и все готово.




$ kubectl apply -f ingress.yaml




Если вы сейчас перейдете на https://my-domain-name.com, должно появиться правильное содержимое.




Источник: https://www.yellowduck.be/posts/k8s-proxy-an-external-site



2023-06-26T23:11:25
DevOps

Настройка доступа Jenkins

Создание пользователей




Сначала необходимо убедиться, что в качестве источника пользователей выбрана внутренняя БД дженкинса.










Далее идём в раздел Управление пользователями.







Там будет кнопка “Создать пользователя”







Настройка прав доступа




Должен быть установлен плагин Matrix Authorization Strategy. Он устанавливается в числе рекомендованных плагинов если вы выбрали этот путь в мастере установки дженкинса.




Этот плагин добавляет в разделе с настройками безопасности таблицу, где столбцы это права, а строки это пользователи.







Важно: при выборе этого способа авторизации не забудьте сразу выдать пользователю admin полные права. Если всё же у вас пропал доступ к настройке системы, то его можно вернуть отредактировав файл /var/jenkins_home/config.xml. Необходимо в строчке <useSecurity>true</useSecurity> написать false и перезапустить дженкинс.



2023-06-20T01:02:03
DevOps

Nexus установка и настройка

Nexus является популярным менеджером репозиториев (repository manager). Он используется для хранения артефактов или прокси, т.е. всё что выкачивается через него, сохраняется в нём.




yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel createrepo



wget http://download.sonatype.com/nexus/3/latest-unix.tar.gz



tar xvf latest-unix.tar.gz -C /opt/



ln -s /opt/nexus-*/ /opt/nexus

useradd -m -r -s /bin/false nexus



chown -R nexus:nexus /opt/nexus-* /opt/sonatype-work /opt/nexus




vim /opt/nexus/bin/nexus.rc

run_as_user="nexus"




vim /etc/systemd/system/nexus.service



[Unit]

Description=nexus service

After=network.target



[Service]

Type=forking

ExecStart=/opt/nexus/bin/nexus start

ExecStop=/opt/nexus/bin/nexus stop

User=nexus

Restart=on-abort



[Install]

WantedBy=multi-user.target







Уменьшить количество потребляемой оперативной памяти:





vim /var/nexus/nexus-3.19.1-01/bin/nexus.vmoptions
меняем
-Xms2703m
-Xmx2703m
на
-Xms512m
-Xmx512m




systemctl daemon-reload && systemctl enable nexus



systemctl start nexus && systemctl status nexus




WEB-интерфейс




http://<Nexus-server-ip-address>:8081




для авторизации в качестве логина используйте
admin
пароль можно посмотреть тут:




cat /opt/sonatype-work/nexus3/admin.password




также по умолчанию пароль может быть следующим:
Login: admin




Password: admin123




Настройка ротации логов Nexus




cat /etc/logrotate.d/nexus




/opt/sonatype-work/nexus3/log/*.log {
daily
dateext
copytruncate
missingok
rotate 3
compress
delaycompress
notifempty
}




отметим что в директории в которой установлен nexux должно быть не меньше 5Gb.




стартуем




systemctl start nexus




добавляем в автозапуск




systemctl enable nexus




логи хранятся тут:




/opt/sonatype-work/nexus3/log/




для удобства создадим симлинк
mkdir /var/log/nexus




ln -s /opt/sonatype-work/nexus3/log/ /var/log/nexus/




========================================================================




Описание работы с данной утилитой




Общий репозиторий:




не забываем включить анонимный доступ чтоб реп работал:
Anonymous — > Allow anonymous users to access the server





Далее переходим к списку репозиториев:




Создаём новый proxy репозиторий (create reposytory — > yum(proxy))




Name: test-repo-epel




ProxyRemote storage:  http://mirror.centos.org/centos-7/7/os/x86_64/




после чего нажимаем create reposytory




Создаём ещё один proxy репозиторий (create reposytory — > yum(proxy))
Name: yum-centos-7-repo_updates
Remote storage: http://mirror.centos.org/centos-7/7/updates/x86_64/




Создаём yum group




Name: yum-repo-group




добавляем в него 2 созданных нами прокси  и сохраняем.




всё, репозиторий создан.




Теперь чтобы использовать его необходимо пройти в раздел:
reposytory -> Repositories -> yum-repo-group
получаем следующую ссылку:
http://192.168.1.171:8081/repository/yum-repo-group/




и на целевой тачке создаем репозиторий:




cat /etc/yum.repos.d/Centos-7-Nexus.repo




[Centos-7-Nexus]

baseurl = http://192.168.1.177:8081/repository/yum-repo-group/

gpgcheck = 1

enabled=1

gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

name = Centos-Nexus




сохраняем и проверяем.




=======================================================================




Общий репозиторий docker:




создаём docker(hosted):
repositories -> create repository -> docker(hosted)




Name: docker-private
type hosted




http: 8083




можно ещё добавить для https




Нажимаем save




создаём docker(proxy):




repositories -> create repository -> docker(proxy)
Name: docker-hub
type proxy
remote storage: https://registry-1.docker.io
docker index: выбирем Use Docker Hub




Нажимаем save




создаём docker(group):




repositories -> create repository -> docker(group)
Name: docker-group
http:8082
и добавляем в него docker-private  docker-hub




Нажимаем save.




На целевой тачке добавляем:




cat /etc/docker/daemon.json
{
"insecure-registries": ["192.168.1.177:8081","192.168.1.177:8082","192.168.1.177:8083"],
"experimental": true
}




Далее необходимо залогиниться в nexus репозитории:
docker login http://192.168.1.177:8082/repository/docker-group




!!! ВАЖНО. Если вы используете прокси, то необходимо убрать его, перезапустить демон, и рестартануть docker(reload не хватит):




mv /etc/systemd/system/docker.service.d/http-proxy.conf /home/

systemctl daemon-reload

systemctl restart docker




проверить, что прокся не задействована вы можете с помощью команды:




docker info




в её выводе не должно быть прокси.




При логине в  192.168.1.177:8082/repository/docker-group в качестве логина и пароля надо указывать или тех пользователей которые вы создали в nexus или главного пользователя с которым вы авторизовались в nexus  admin admin123




чтобы выкачать образ необходимо указывать адрес источника, т.е.:
docker pull 192.168.1.177:8082/httpd




docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.1.177:8082/nginx latest e445ab08b2be 37 hours ago 126MB
192.168.1.177:8082/httpd latest ee39f68eb241 12 days ago 154MB




переименуем наш образ и загрузим его в nexus:
docker tag 192.168.1.177:8082/nginx 192.168.1.177:8082/nginx33:3




docker push 192.168.1.177:8082/nginx33:3




========================================




чтобы использовать nexus как прокси для скачивания обновлений или докер образов надо пройти в:
System -> HTTP -> HTTP(s) Proxy 
указываем ip и port нашего прокси, также можем задать список адресов которые исключаются из прокси(т.е. обращаясь к ним запрос не пойдёт через проксю)
Hosts to exclude from HTTP/HTTPS proxy
и нажимаем saveне забываем логиниться
docker login 192.168.1.177:8082




=========================================




чтобы использовать nexus как прокси для установки через pip
надо создать репозиторий:
Create repository — pypi (proxy) задаём имя (произвольное) в качестве remote storage указываем
https://pypi.org
сохраняем, далее создаём pypi(group) задаём имя (произвольное) добавляем в группу ранее созданый прокси репозиторий и сохраняем
получаем ссылку группы:
http://192.168.1.177:8082/repository/pypi-repo/




далее на целевой тачке создаём файл pip.conf




cat /etc/pip.conf

[global]

index = http://192.168.1.177:8082/repository/pypi-repo/pypi

index-url = http://192.168.1.177:8082/repository/pypi-repo/simple




и запускаем установку так:




pip install pypi-install --trusted-host 192.168.1.177




Источник: https://sidmid.ru/nexus-install-and-settings/



2023-06-02T15:55:17
DevOps

Kubernetes — Автоскейлинг приложений при помощи Prometheus и KEDA

Kubernetes позволяет автоматически масштабировать приложения (то есть Pod в развертывании или ReplicaSet) декларативным образом с использованием спецификации Horizontal Pod Autoscaler.




По умолчанию критерий для автоматического масштабирования — метрики использования CPU (метрики ресурсов), но можно интегрировать пользовательские метрики и метрики, предоставляемые извне.




Вместо горизонтального автомасштабирования подов, применяется Kubernetes Event Driven Autoscaling (KEDA) — оператор Kubernetes с открытым исходным кодом. Он изначально интегрируется с Horizontal Pod Autoscaler, чтобы обеспечить плавное автомасштабирование (в том числе до/от нуля) для управляемых событиями рабочих нагрузок. Код доступен на GitHub.




Краткий обзор работы системы





На схеме — краткое описание того, как все работает:




  1. Приложение предоставляет метрики количества обращений к HTTP в формате Prometheus.



  2. Prometheus настроен на сбор этих показателей.



  3. Скейлер Prometheus в KEDA настроен на автоматическое масштабирование приложения на основе количества обращений к HTTP.




Теперь подробно расскажу о каждом элементе.




KEDA и Prometheus




Prometheus — набор инструментов для мониторинга и оповещения систем с открытым исходным кодом, часть Cloud Native Computing Foundation. Собирает метрики из разных источников и сохраняет в виде данных временных рядов. Для визуализации данных можно использовать Grafana или другие инструменты визуализации, работающие с API Kubernetes.




KEDA поддерживает концепцию скейлера — он действует как мост между KEDA и внешней системой. Реализация скейлера специфична для каждой целевой системы и извлекает из нее данные. Затем KEDA использует их для управления автоматическим масштабированием.




Скейлеры поддерживают нескольких источников данных, например, Kafka, Redis, Prometheus. То есть KEDA можно применять для автоматического масштабирования развертываний Kubernetes, используя в качестве критериев метрики Prometheus.




KEDA Prometheus ScaledObject




Скейлер действует как мост между KEDA и внешней системой, из которой нужно получать метрики. ScaledObject — настраиваемый ресурс, его необходимо развернуть для синхронизации развертывания с источником событий, в данном случае с Prometheus.




ScaledObject содержит информацию о масштабировании развертывания, метаданные об источнике события (например, секреты для подключения, имя очереди), интервал опроса, период восстановления и другие данные. Он приводит к соответствующему ресурсу автомасштабирования (определение HPA) для масштабирования развертывания.




Когда объект ScaledObject удаляется, соответствующее ему определение HPA очищается.




Вот определение ScaledObject для нашего примера, в нем используется скейлер Prometheus:




apiVersion: keda.k8s.io/v1alpha1

kind: ScaledObject

metadata:

 name: prometheus-scaledobject

 namespace: default

 labels:

  deploymentName: go-prom-app

spec:

 scaleTargetRef:

   deploymentName: go-prom-app

 pollingInterval: 15

 cooldownPeriod:  30

 minReplicaCount: 1

 maxReplicaCount: 10

 triggers:

 - type: prometheus

  metadata:

    serverAddress:

http://prometheus-service.default.svc.cluster.local:9090

    metricName: access_frequency

    threshold: '3'

    query: sum(rate(http_requests[2m]))




Учтите следующие моменты:




  1. Он указывает на Deployment с именем go-prom-app.



  2. Тип триггера — Prometheus. Адрес сервера Prometheus упоминается вместе с именем метрики, пороговым значением и запросом PromQL, который будет использоваться. Запрос PromQL — sum(rate(http_requests[2m])).



  3. Согласно pollingInterval, KEDA запрашивает цель у Prometheus каждые пятнадцать секунд. Поддерживается минимум один под (minReplicaCount), а максимальное количество подов не превышает maxReplicaCount (в данном примере — десять).




Можно установить minReplicaCount равным нулю. В этом случае KEDA активирует развертывание с нуля до единицы, а затем предоставляет HPA для дальнейшего автоматического масштабирования. Возможен и обратный порядок, то есть масштабирование от единицы до нуля. В примере мы не выбрали ноль, поскольку это HTTP-сервис, а не система по запросу.




Магия внутри автомасштабирования




Пороговое значение используют в качестве триггера для масштабирования развертывания. В нашем примере запрос PromQL sum(rate (http_requests [2m])) возвращает агрегированное значение скорости HTTP-запросов (количество запросов в секунду), ее измеряют за последние две минуты.




Поскольку пороговое значение равно трем, значит, будет один под, пока значение sum(rate (http_requests [2m])) меньше трех. Если же значение возрастает, добавляется дополнительный под каждый раз, когда sum(rate (http_requests [2m])) увеличивается на три. Например, если значение от 12 до 14, то количество подов — четыре.




Теперь давайте попробуем настроить!




Установка KEDA




Вы можете развернуть KEDA несколькими способами, они перечислены в документации. Я использую монолитный YAML:




[root@kub-master-1 ~]# wget https://github.com/kedacore/keda/releases/download/v2.1.0/keda-2.1.0.yaml
[root@kub-master-1 ~]# kubectl apply -f keda-2.1.0.yaml




ну или можно установить через helm




helm repo add kedacore https://kedacore.github.io/charts
helm repo update
kubectl create namespace keda
helm install keda kedacore/keda —namespace keda




я ставил через монолитный файл.
проверим что всё поднялось:




[root@kub-master-1 ~]# kubectl get all -n keda

NAME                                          READY   STATUS    RESTARTS   AGE

pod/keda-metrics-apiserver-57cbdb849f-w7rfg   1/1     Running   0          70m

pod/keda-operator-58cb545446-5rblj            1/1     Running   0          70m



NAME                             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE

service/keda-metrics-apiserver   ClusterIP   10.100.134.31   <none>        443/TCP,80/TCP   70m



NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE

deployment.apps/keda-metrics-apiserver   1/1     1            1           70m

deployment.apps/keda-operator            1/1     1            1           70m



NAME                                                DESIRED   CURRENT   READY   AGE

replicaset.apps/keda-metrics-apiserver-57cbdb849f   1         1         1       70m

replicaset.apps/keda-operator-58cb545446            1         1         1       70m





3. Пример работы




создаём namespace




kubectl create ns my-site




запускаем обычное приложение например apache:




[root@kub-master-1 ~]# cat my-site.yaml




---

apiVersion: apps/v1

kind: Deployment

metadata:

  name: my-deployment-apache

  namespace: my-site

spec:

  replicas: 1

  selector:

    matchLabels:

      app: apache # по вот этому лейблу репликасет цепляет под

# тут описывается каким мокаром следует обновлять поды

  strategy:

    rollingUpdate:

      maxSurge: 1  # указывает на какое количество реплик можно увеличить

      maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить

#т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под)

    type: RollingUpdate

## тут начинается описание контейнера

  template:

    metadata:

      labels:

        app: apache  # по вот этому лейблу репликасет цепляет под

    spec:

      containers:

        - image: httpd:2.4.43

          name: apache

          ports:

            - containerPort: 80

# тут начинаются проверки по доступности

          readinessProbe: # проверка готово ли приложение

            failureThreshold: 3 #указывает количество провалов при проверке

            httpGet:  # по сути дёргает курлом на 80 порт

              path: /

              port: 80

            periodSeconds: 10 #как часто должна проходить проверка (в секундах)

            successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок

            timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда

          livenessProbe: #проверка на жизнь приложения, живо ли оно

            failureThreshold: 3

            httpGet:

              path: /

              port: 80

            periodSeconds: 10

            successThreshold: 1

            timeoutSeconds: 1

            initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд



# тут начинается описание лимитов для пода

          resources:

            requests: #количество ресурсов которые резервируются для pod на ноде

              cpu: 60m

              memory: 200Mi

            limits: #количество ресурсов которые pod может использовать(верхняя граница)

              cpu: 120m

              memory: 300Mi





[root@kub-master-1 ~]# cat my-site-service.yaml




---

apiVersion: v1

kind: Service

metadata:

  name: my-service-apache # имя сервиса

  namespace: my-site

spec:

  ports:

  - port: 80  # принимать на 80

    targetPort: 80 # отправлять на 80

  selector:

    app: apache  #отправлять на все поды с данным лейблом

  type: ClusterIP





[root@kub-master-1 ~]# cat my-site-ingress.yaml




---

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

  name: my-ingress

  namespace: my-site

spec:

  rules:

  - host: test.ru  #тут указывается наш домен

    http:

      paths:  #список путей которые хотим обслуживать(он дефолтный и все запросы будут отпаврляться на бэкенд, т.е. на сервис my-service-apache)

      - backend:

          serviceName: my-service-apache  #тут указывается наш сервис 

          servicePort: 80 #порт на котором сервис слушает

#        path: /  все запросы на корень '/' будут уходить на наш сервис





применяем:




[root@kub-master-1 ~]# kubectl apply -f my-site.yaml -f my-site-service.yaml -f my-site-ingress.yaml




проверяем:




[root@kub-worker-1 ~]# curl test.ru
<html><body><h1>It works!</h1></body></html>




[root@kub-master-1 ~]# kubectl get all -n my-site




NAME                                        READY   STATUS    RESTARTS   AGE

pod/my-deployment-apache-859486bd8c-k6bql   1/1     Running   0          20m



NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE

service/my-service-apache   ClusterIP   10.100.255.190   <none>        80/TCP    20m



NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE

deployment.apps/my-deployment-apache   1/1     1            1           20m



NAME                                              DESIRED   CURRENT   READY   AGE

replicaset.apps/my-deployment-apache-859486bd8c   1         1         1       20m





будем автоскейлить — для примера по метрике nginx nginx_ingress_controller_requests




запрос в prometheus будет следующий:




sum(irate( nginx_ingress_controller_requests{namespace=»my-site»}[3m] )) by (ingress)*10




т.е. считаем общее количество запросов в неймспейс my-site за 3 минуты




создаём keda сущность:




[root@kub-master-1 ~]# cat hpa-keda.yaml




apiVersion: keda.sh/v1alpha1

kind: ScaledObject

metadata:

  name: prometheus-scaledobject

  namespace: my-site

spec:

  scaleTargetRef:

    name: my-deployment-apache

  minReplicaCount: 1   # Optional. Default: 0

  maxReplicaCount: 8 # Optional. Default: 100

  triggers:

  - type: prometheus

    metadata:

      serverAddress: http://prometheus-kube-prometheus-prometheus.monitoring.svc.cluster.local:9090

      metricName: nginx_ingress_controller_requests

      threshold: '100'

      query: sum(irate(nginx_ingress_controller_requests{namespace="my-site"}[3m])) by (ingress)*10




тут мы указываем в каком namespace нам запускаться:
namespace: my-site




указываем цель, т.е. наш deployment:
name: my-deployment-apache




задаём минимальное и максимальное количество реплик
minReplicaCount: 1 # значение по умолчанию: 0
maxReplicaCount: 8 # значение по умолчанию: 100




есть ещё 2 стандартные переменные отвечающие за то когда поды будут подыматься и убиваться:
pollingInterval: 30 # Optional. Default: 30 seconds
cooldownPeriod: 300 # Optional. Default: 300 seconds




указываем адрес нашего prometheus




serverAddress: http://prometheus-kube-prometheus-prometheus.monitoring.svc.cluster.local:9090
адрес идёт в виде сервис.неймспейс.svc.имя_кластера




указываем нашу метрику:
metricName: nginx_ingress_controller_requests




указываем пороговое значение при котором начнётся автоскейлинг:
threshold: ‘100’




и соответственно наш запрос в prometheus:
query:




всё можно применять:




[root@kub-master-1 ~]# kubectl apply -f hpa-keda.yaml




проверяем:




[root@kub-master-1 ~]# kubectl get horizontalpodautoscalers.autoscaling -n my-site

NAME                               REFERENCE                         TARGETS       MINPODS   MAXPODS   REPLICAS   AGE

keda-hpa-prometheus-scaledobject   Deployment/my-deployment-apache   0/100 (avg)   1         8         1          68m





[root@kub-master-1 ~]# kubectl get pod -n my-site

NAME                                    READY   STATUS    RESTARTS   AGE

my-deployment-apache-859486bd8c-v59b8   1/1     Running   0          37m





а теперь накрутим запросов:




[root@kub-worker-1 ~]# for i in {1..5000}; do curl test.ru; done




проверяем:




[root@kub-master-1 ~]# kubectl get horizontalpodautoscalers.autoscaling -n my-site

NAME                               REFERENCE                         TARGETS            MINPODS   MAXPODS   REPLICAS   AGE

keda-hpa-prometheus-scaledobject   Deployment/my-deployment-apache   34858m/100 (avg)   1         8         7          71m





как видим количество запросов превысило наш лимит и стали создаваться новые поды:




[root@kub-master-1 ~]# kubectl get pod -n my-site

NAME                                    READY   STATUS    RESTARTS   AGE

my-deployment-apache-859486bd8c-6885f   1/1     Running   0          49s

my-deployment-apache-859486bd8c-6mcq4   1/1     Running   0          64s

my-deployment-apache-859486bd8c-cdb6z   1/1     Running   0          64s

my-deployment-apache-859486bd8c-kpwb8   1/1     Running   0          64s

my-deployment-apache-859486bd8c-rmw8d   1/1     Running   0          49s

my-deployment-apache-859486bd8c-v59b8   1/1     Running   0          39m

my-deployment-apache-859486bd8c-xmv28   1/1     Running   0          49s





прекращаем запросы и спустя 5 минут, указанное в переменной cooldownPeriod ненужные поды будут убиты:




[root@kub-master-1 ~]# kubectl get pod -n my-site

NAME                                    READY   STATUS        RESTARTS   AGE

my-deployment-apache-859486bd8c-6885f   0/1     Terminating   0          6m35s

my-deployment-apache-859486bd8c-6mcq4   1/1     Running       0          6m50s

my-deployment-apache-859486bd8c-cdb6z   0/1     Terminating   0          6m50s

my-deployment-apache-859486bd8c-kpwb8   0/1     Terminating   0          6m50s

my-deployment-apache-859486bd8c-rmw8d   0/1     Terminating   0          6m35s

my-deployment-apache-859486bd8c-v59b8   0/1     Terminating   0          44m

my-deployment-apache-859486bd8c-xmv28   0/1     Terminating   0          6m35s



[root@kub-master-1 ~]# kubectl get pod -n my-site

NAME                                    READY   STATUS    RESTARTS   AGE

my-deployment-apache-859486bd8c-6mcq4   1/1     Running   0          7m48s





Источник: https://sidmid.ru/kubernetes-автоскейлинг-приложений-при-помощ/



SOPS + Age: Шифруем секреты

Это краткая напоминалка для шифрования YAML-файлов с секретами, которые публикуются в Git. Удобно для дальнейшей интеграции с Flux2ArgoCD (через Helm Secrets плагин)




Вместо тысячи слов: Age is a simple, modern and secure file encryption tool, format, and Go library. Рекомендуется пользоваться age вместо GPG – по крайней мере, так рекомендуют сами разработчики sops.




Инструкция ниже была выполнена на Ubuntu 20.04 в WSL2




Getting started




  • Необходимо сформировать приватный и публичный ключи, на основе которых будет производиться шифрование:




# создать каталог, где age по умолчанию будет искать ключи

mkdir -p $HOME/.config/sops/age/

 

# сгенерировать ключи

age-keygen -o $HOME/.config/sops/age/keys.txt

 

# добавить публичный ключ в переменную

PUB_KEY=$(cat $HOME/.config/sops/age/keys.txt | grep "public" | awk '{print $4}')




  • В данном примере будут шифроваться yaml файлы с чувствительными данными. Поэтому для необходимых полей yaml необходимо создать маску. В encrypted_regex добавить необходимые значения полей, а в age – публичный ключ, сформированный на предыдущем шаге в файле $HOME/.config/sops/age/key.txt:




cat > $HOME/.sops.yaml << EOF

creation_rules:

  - encrypted_regex: '^(data|key|password)$'

    age: $(echo $PUB_KEY)

EOF




К файлу .sops.yaml и keys.txt sops будет обращаться при каждом выполнении.




Так как $HOME/.config/sops/age/keys.txt – путь по умолчанию, sops не требуется явно передавать путь к файлу ключей. Но при необходимости его также можно задавать через переменную окружения – export SOPS_AGE_KEY_FILE=$HOME/.config/sops/age/keys.tx




  • Теперь можно создать файл-пример:




cat > $HOME/secret.yaml << EOF

apiVersion: v1

kind: Secret

metadata:

  name: mysecret

type: Opaque

data:

  USER_NAME: bob

  PASSWORD: strongpass

EOF




  • И при наличии всех необходимых данных выполнить шифрование:




sops -e -i secret.yaml




  • На выходе будет файл с тем же именем, но с шифрованным содержимым в поле data:




cat secret.yaml

apiVersion: v1

kind: Secret

metadata:

    name: mysecret

type: Opaque

data:

    USER_NAME: ENC[AES256_GCM,data:BQ6O,iv:XyjcRI5/TzDykCQo6a9FoDotHjJlYNGH+4Yq30F+5k4=,tag:YNyd8LnwMnmHe0TUm5wKhg==,type:str]

    PASSWORD: ENC[AES256_GCM,data:dD3prw2Cs9VOxw==,iv:2adiZTUmXrIHnpwrgAvJvsMafvrG+DDGXhUKD/C9nio=,tag:Xbl9NCuVdFRwED1AuXFtQA==,type:str]

sops:

    kms: []

    gcp_kms: []

    azure_kv: []

    hc_vault: []

    age:

        - recipient: age10teuyr66yq0glkkdp8w8adpvuty7xl4vhp6ergna8k95r68g9p7q5gvt94

          enc: |

            -----BEGIN AGE ENCRYPTED FILE-----

            YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGdVRaTU1OT2g2SkhhK2tm

            ckpCZ0pWanBTYXJBdloybXVvYzNKeUFLM3lnCnUvd2FtbDAzZFlIY2ZHTEwyYmFs

            MWl0VmNldnk0VzBzSUdCZmJzZ0VZaU0KLS0tIFJ6ZzJyZmxKYUE5cjRVdVViVzV6

            ZFVLN3V0N3dUQ1lPSjUxZE0xMXh0SjgKFNwNL2bDPhuTZU7qb46ZPQ+qWm0dcSUf

            mt2xZismI0/g9oZH1K4CzMkrgYHDketCDPFLDZ9lRPha7jZzY9lKNA==

            -----END AGE ENCRYPTED FILE-----

    lastmodified: "2022-12-29T10:46:46Z"

    mac: ENC[AES256_GCM,data:ZEKJyGWWvKlP2/nrxosy7tLbiNx0p6Eu0+wYLz69NHjwa1bzIWAzVNXKQgZy1fWLT/AGlgwqTfx5zg8bg0iv43dHqL+NhIhTrqMLPlmYO/IiCn9PBfSY0UVdUwoz2E9QLCDHFaBvOqK5Q9EVkAApjsTwC39KlofPkwB5f+5FKqY=,iv:6hfqwbsUWHxkEWILMa5SrRnpPM81W2lX4gNntbxvoW0=,tag:lWl47uddfa4N/lQ0J+0fBA==,type:str]

    pgp: []

    encrypted_regex: ^(data|key|password)$

    version: 3.7.3




  • Для расшифровки:




sops -d -i secret.yaml

 

apiVersion: v1

kind: Secret

metadata:

    name: mysecret

type: Opaque

data:

    USER_NAME: bob

    PASSWORD: strongpass




  • При необходимости можно задать расширение (например, enc), указав, что файл зашифрован:




sops -e secret.yaml > secret.yaml.enc




  • И дешифровать




sops -d --input-type yaml --output-type yaml secret.yaml.enc




Важно указать явно input и output формат – yaml. Этого нет в документации, см issue




VSCode extensions




Для удобства работы с шифрованными секретами можно установить плагин для VSC, который позволяет налету производить расшифровку. Плагин не требует настройки, если путь для хранения публичныхприватных ключей в linux лежит по пути $HOME/.config/sops/age/ – можно сразу открывать шифрованные файлы после установки и работать с ними.




Источник: https://it-lux.ru/sops-age/



2023-02-23T02:40:42
DevOps

CI/CD для фронтенда: обзор инструментов и практик для автоматизации разработки

Процессы разработки веб-приложений со временем усложняются, и девопсам труднее разбираться в их нюансах. Кроме того, девопсы, помимо фронта, занимаются и бэкендом, и кучей других задач, которые решать могут только они.




Мне кажется, это хорошая идея — разобраться, как ваше приложение будет автоматически собираться и деплоиться. Тем более сейчас (на самом деле всегда) тренд на T-shaped people — спецов в своей области, которые немного разбираются в смежных.




Что такое CI/CD







Для начала небольшой ликбез. CI/CD расшифровывается как Continuous Integration и Continuous Delivery aka Deployment — то есть непрерывная интеграция и непрерывная доставка. Зачем это нужно?




Чаще всего конечная цель разработки — приложение. Чтобы им пользоваться, люди должны получить к нему доступ: либо скачать из стора и установит. Если это сайт — вбить в адресную строку URL и открыть страничку. Чтобы мобильное приложение попало в стор, его нужно туда загрузить. В случае с сайтами нужно загрузить наши HTML/JS/CSS-файлы.




Вроде бы все просто. Но загружать файлы вручную как минимум неудобно:




  • Нужно находиться за компьютером, на котором эти файлы есть.



  • Когда файлы загружает человек, он может забыть что-то выгрузить или выгрузить что-то не то.




Процесс неплохо бы автоматизировать — это и есть деплоймент, желтая петля на картинке. В статье я упомяну именно деплой- и релиз-шаги. Более продвинутые темы оперирования и мониторинга не трогаю: не хочется совсем уж отнимать хлеб у девопсов 🙂




Голубая петля, CI, — это то, что мы делаем после того, как доработали новый функционал, и перед тем, как он пойдет в деплой, чтобы стать доступным пользователям.




Что входит в CI




  • линтеры;



  • тесты;



  • подготовка продакшен-билда.




Линтеры




Зачем




Линтеры — это статические анализаторы кода, которые его проверяют, не запуская. Они позволяют сократить время на код-ревью и избавить разработчиков от рутинных задач: проверки стилистики кода (пробелы, точки с запятыми и длина строки); поиска проблем и потенциальных багов: неиспользованные фрагменты кода, заведомо опасные или переусложненные конструкции.




Как







  • ESLlint — де-факто стандартный линтер для JavaScript.



  • TSLint — был основным линтером для TypeScript, однако разработчики отказываются от его поддержки в пользу ESLint.



  • Prettier — не совсем линтер, скорее, форматтер, который следит за единой стилистикой кода; без проблем интегрируется с ESLint и TSLint.



  • stylelint — линтер для CSS и самых популярных его диалектов (SASS, LESS), для которых у него есть плагины.




Тесты




Зачем




Перед тем как деплоить приложение, или даже строже: перед тем как вливать его в мастер, мы хотим убедиться в его стабильности. Мы хотим знать, что приложение не сломается после запуска и что основные сценарии использования работают. И мы хотим делать это автоматически.




Как







  • JestMochaJasmine — фреймворки для организации и запуска тестов; в последнее время наиболее популярен Jest, так как он идет из коробки с Create React App.



  • Testing LibraryEnzyme — утилиты, в первую очередь нацеленные на тестирование веб-приложений (рендеринг, симуляция кликов и т. п.).



  • selenium-webdriverCypress — инструменты для тестирования end-to-end, то есть когда будет действительно запускаться браузер и туда будут отправляться команды, эмулирующие действия пользователя (клики, нажатия клавиш и т. п.).




Подготовка продакшен-сборки




Что и зачем




Сборка — это преобразование исходных файлов так, чтобы их можно было раздавать сервером как веб-сайт (то есть как набор HTML-/JS-/CSS-файлов, которые понимает браузер), публиковать в менеджере пакетов (если вы пишете библиотеку, фреймворк или утилиту), использовать как расширения для браузера, приложение на Electron и др.




В процессе разработки и в продакшене приложение запускается и работает по-разному. И характеристики нам важны разные. В процессе разработки мы хотим, чтобы приложение быстро пересобиралось и мы видели обновленный результат. При этом не важно, сколько оно весит, ведь оно раздается с локальной машины. В продакшене нам не важно (в разумных пределах, конечно), сколько времени приложение собирается, ведь мы его собираем один раз и потом просто раздаем сервером.




Условно продакшен-сборка состоит из таких процессов:




  • Разрешение импортов. Браузеры начали понимать модульность только недавно, и то до сих пор не все. Необходимо разобраться, в каком порядке запускать скрипты и как передавать результаты их исполнения другим скриптам.



  • Минификация и обфускация. Собранный код весит меньше, чем исходники, и его сложнее анализировать. Этим мы усложняем реверс-инжиниринг.



  • Вшивание переменных окружения. Одно и то же приложение может работать в разных средах. Простейший пример — на тестовом сервере и на продакшене: в этом случае необходимо сбилдить приложения два раза, один раз — когда в окружении задан адрес апи тестового сервера, второй раз — продакшен-сервера.




Как







  • webpackParcelRollup, SystemJS, gulpGrunt — основные сборщики приложений, которые решают большинство упомянутых задач.



  • Dotenvdotenv-cli — npm-пакеты, которые упрощают работу с переменными окружения, особенно при разработке.




Дополнительно




Очень полезно после билда и перед деплоем создавать файл version.json. Этот файл будет содержать информацию о версии приложения, о времени билда, фрагмент хеша коммита, из которого приложение было собрано.




Храните этот файл таким образом, чтобы он был легко доступен рядом с веб-приложением. Например, по адресу: https://your-site.com/version.json.




Такое простое действие поможет вам и другим членам команды (в первую очередь тестировщикам) быстро определять версию приложения, которая запущена в данном окружении, и отслеживать деплои.




Итог. Npm Scripts




Все эти процессы — это integration из CI, но пока что не очень continuous. Чтобы их автоматизировать, необходимо потратить время (один раз) и сконфигурировать их так, чтобы они запускались одной командой в командной строке.




Для этого отлично подходят npm-скрипты. В итоге все 3 предыдущих процесса можно свести к запуску трех команд, который будет похож на что-то вроде:




npm run lint
npm run test
npm run build




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




Бонус. Git Hooks




Зачем




Чтобы не забывать запускать линтеры и тесты. Их запуск можно автоматизировать с помощью Git Hooks, то есть линтеры и тесты будут запускаться, например, перед каждым коммитом.




Как




  • Husky — позволяет привязывать npm-скрипты к Git Hooks внутри package.json.



  • lint-staged — позволяет запускать линтеры только для тех файлов, которые подготовлены для коммита.




Что входит в CD




  • версионирование и релиз;



  • деплоймент.




Версионирование и релиз




Зачем




Версионирование решает большое количество проблем: и при разработке библиотек и фреймворков, и связанных с совместимостями. Сфокусируемся на проблемах, возникающих при разработке приложений для конечных пользователей. Их помогают решить:




  1. Маркеры стабильных ревизий. Упрощают поиск последней стабильной ревизии при необходимости откатить версию приложения (если, например, критический баг попал в продакшен).



  2. Именования для коммуникации. У вас появляется возможность обсуждать заливки, не называя их «то, где мы добавили профиль» или «то, где мы пофиксили регистрацию», а используя номера версий — емкие и однозначные, писать более точные ченжлоги, более эффективно исследовать и воспроизводить баги.




Как







  • Semantic Versioning — методология для формирования номера версии. Одна из многих, но именно эта используется для версионирования npm-пакетов (ее удобно совмещать с версией в package.json).



  • Npm versionyarn version — команды, которые увеличивают версию вашего приложения. Они автоматически меняют версию в package.json, делают коммит с соответствующим сообщением и ставят тег, в котором будет имя новой версии.




Деплоймент




Деплоймент — это доставка и выгрузка файлов в место, откуда они будут раздаваться. То, как происходит деплой в значительной мере зависит от того, как именно хостится ваше приложение. Это может быть один из многих вариантов, например: AWS S3 Bucket / AWS CloudFront / другой сервис AWS, коих множество, Heroku/Dokku, VPS/VPH.




Зачем




Очевидно, что если мы не выгрузим наше приложение на сервера, откуда оно будет хоститься, люди не смогут им пользоваться.
Процесс нужно автоматизировать: один раз потратить время на написание скрипта, чтобы сэкономить большое количество времени и нервов, а также снизить риск, связанный с человеческим фактором.




Как







Деплоймент — это просто выгрузка файлов на другой сервер. Разница лишь в протоколе, по которому она будет происходить:




  • SSH — с некоторыми оговорками можно представить как пуш в некий удаленный (в смысле находящийся далеко) репозиторий.



  • HTTP — простой и знакомый фронтендерам способ, когда каждый файл отправляется в теле соответствующего HTTP-запроса.



  • FTP — самый старый из перечисленных протоколов, для которого можно найти клиент на Node.js, но, возможно, придется попотеть, настраивая его.




Операция выгрузки файлов может быть свернута до единого npm script, который будет запускать файл Node.js. Большинство API работают на Node.js (к примеру AWS).




Итог




По аналогии с CI мы получим несколько простых npm-скриптов, которые позволят запускать более сложные и ответственные процессы.




Пайплайны




Если переводить слово pipeline с английского в контексте computer science, одним из переводов будет «конвейер». И это слово хорошо описывает ситуацию.




Зачем




Если взять упрощенную аналогию с машиной, то сначала нам нужно собрать двигатель, ходовую из колес и осей. После соединить их вместе, чтобы двигатель крутил колеса. Затем на все это сверху повесить корпус, чтобы водитель не мог под дождем. А в конце покрасить, чтобы было красиво 🙂




Существуют взаимозависимости и порядок процессов. Например, нет смысла деплоить приложение, если тесты упали. Упрощенно конвейер для нашего приложения выглядит так: линтинг и тесты — версионирование — билд — деплой.




Именно здесь вступают в дело пайплайны — как инструмент, который описывает и запускает конвейер для процессов CI/CD.




Как










Почти все, что я привел в списке, — это хостинги репозиториев, кроме Jenkins’а (который я добавил для полноты картины, чтобы было ясно, что такие инструменты не обязательно являются частью хостинга репозиториев).




Далее я приведу несколько примеров, как это выглядит в GitLab Pipelines. Для примеров я взял именно GitLab по нескольким причинам. У меня есть опыт плотной работы с этим сервисом. Бесплатный аккаунт на GitLab предоставляет хороший пакет, связанный с пайплайнами, которого с головой хватит, чтобы потренироваться на пет-проекте. То же относится к standalone GitLab-серверу. Также он дает общее понимание, как настраиваются пайплайны. Лично мне было нетрудно по аналогии с GitLab разобраться с тем, что предлагали Bitbucket Pipelines.




GitLab CI/CD




Как это выглядит. Для каждого запушенного коммита запускается пайплайн. Ниже можно увидеть список пайплайнов, которые запускались для разных коммитов.







Рис. 1. Успешно завершенные пайплайны




Пайплайн состоит из шагов (steps). Степы, в свою очередь, состоят из задач (jobs). Ниже можно увидеть развернутую структуру пайплайна. Колонки Setup, Code_quality и далее — это steps. Каждый блок с зеленой иконкой — это отдельная job.







Рис. 2. Декомпозиция пайплайна




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







Рис. 3. Пайплайн, завершившийся неудачей, так как линтеры упали




.gitlab-ci.yml




Как это настраивать. Пайплайн описывается в файле .gitlab-ci.yml, который должен лежать в корневой папке репозитория.




Я остановлюсь лишь на базовых примерах, а полную документацию вы сможете найти здесь.




image: node:8

variables:
 REACT_APP_ENV_NAME: $CI_ENVIRONMENT_NAME

stages:
 - setup
 - code_quality
 - testing
 - semver
 - deployment




Строки 1-11 .gitlab-ci.yaml




image — указывает, в каком докер-контейнере должен запускаться пайплайн. Если очень коротко, докер — это технология, позволяющая получить предсказуемую среду выполнения. В данном случае мы хотим запускаться в условном Linux, на котором установлена 8-я версия Node.js.




variables — позволяет явно определить переменные окружения во время работы пайплайна. В нашем примере берем встроенную переменную, которая содержит имя энвайронмента, для которого работает пайплайн, и переприсвает его в переменную, которая будет доступна внутри упакованного приложения. В данном случае это делалось для интеграции с системой трекинга ошибок — Sentry.




stages — описывает очередность выполнения задач. Ставим зависимости, линтим скрипты и стили, потом тестируем, после чего уже можем деплоить. Выглядит это как массив строчных значений, которые используются для маркировки задач. Эти же стадии изображены на рис. 2.




Jobs & Scripts




dependencies:installation:
 stage: setup
 cache:
   paths:
     - node_modules/
 script:
   - yarn --prefer-offline --no-progress --non-interactive --frozen-lockfile
 tags:
   - web-ci

lint:scripts:
 stage: code_quality
 cache:
   paths:
     - node_modules/
 script:
   - yarn run lint:scripts:check --max-warnings 0
 only:
   changes:
     - src/**/*.{ts,tsx}
 tags:
   - web-ci

lint:styles:
 stage: code_quality
 cache:
   paths:
     - node_modules/
 script:
   - yarn run lint:styles:check
 only:
   changes:
     - src/**/*.{css,scss}
 tags:
   - web-ci


unit:testing:
 stage: testing
 cache:
   paths:
     - node_modules/
 only:
   changes:
     - src/**/*.{ts,tsx}
 script:
   - yarn test
 tags:
   - web-ci




Строки 13-60 .gitlab-ci.yaml




jobs — далее от корня указываются названия задач и потом вглубь — их описание. Ключевыми параметрами джобы выступают стейджи, то есть привязки конкретной джобы к стейджу. Это определяет, после каких джоб она будет исполнена.




script — набор команд, которые будут выполнены в процессе работы джобы. Для dependencies installation мы видим, что это всего одна команда — yarn — c аргументами, которые говорят не качать лишнего, если оно есть в кеше.




Подобным образом это работает с линтом скриптов и стилей. Обратите внимание, что и скрипты, и стили привязаны к одному стейджу. Это значит, что по возможности они будут идти параллельно.




only и exlude позволяют определить, когда джоба должна работать, а когда нет. Например, мы видим, что линтинг скриптов происходит только при изменениях в рамках .ts- и .tsx-файлов, CSS- и SCSS-стилей.




Таким же образом можно сделать джобу деплоя доступной только для мастер-ветки.




Версионирование




Версионирование — одна из путающих задач при построении пайплайна. Пайплайн запускается на одном из коммитов, а версионирование само по себе провоцирует создание нового коммита, в котором будет изменена версия package.json и проставлен новый тег. Нам придется запушить в репозиторий из пайплайна и, таким образом, один пайплайн спровоцирует другой пайплайн.




.semver_script: &semver_script
 stage: semver
 when: manual
 only:
   - master
 except:
   refs:
     - /^vd+.d+.d+$/
 tags:
   - web-ci
 script:
   - mkdir -p ~/.ssh && chmod 700 ~/.ssh
   - ssh-keyscan $CI_SERVER_HOST >> ~/.ssh/known_hosts && chmod 644 ~/.ssh/known_hosts
   - eval $(ssh-agent -s)
   - ssh-add <(echo "$SSH_PRIVATE_KEY")
   - git remote set-url --push origin git@$CI_SERVER_HOST:$CI_PROJECT_PATH.git
   - git config --local --replace-all user.email "
 noreply@yourmail.com"
   - git config --local --replace-all user.name "Gitlab CI"
   - git checkout $CI_COMMIT_REF_NAME
   - git reset --hard origin/$CI_COMMIT_REF_NAME
   - npm version $SEMVER_LEVEL
   - git push -u origin $CI_COMMIT_REF_NAME --tags

semver:minor:
 <<: *semver_script
 variables:
   SEMVER_LEVEL: minor

semver:patch:
 <<: *semver_script
 variables:
   SEMVER_LEVEL: patch




Строки 62-93 .gitlab-ci.yaml




Этот фрагмент уже более сложный. Здесь описаны две аналогичные джобы: для инкремента минорной и патч-версий соответственно. Скрипт описывает операции, которые позволят пушить из пайплайна в свой же репозиторий:




  • Добавление приватного SSH-ключа, который хранится в переменных окружения и который имеет доступ для пуша в репозиторий.



  • Добавление хоста репозитория в список известных хостов.



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




Чтобы не копировать этот фрагмент для минорной и патч-версий, здесь используется фича YAML-файлов, которая называется YAML anchor. Благодаря подобным фичам YAML-файлы становятся лучшим форматом для описания конфигураций.




Деплоймент и переменные окружения







Рис. 4. Веб-интерфейс гитлаба для управления окружениями




На рис. 4 показан веб-интерфейс гитлаба для создания и редактирования деплоймент-окружений. После того как они созданы здесь, их можно использовать в .gitlab-ci.yaml.




Ниже приведен фрагмент конфигурации деплоймента на примере выгрузки результатов билда в AWS S3 Bucket. Здесь также использован YAML anchor для исключения дублирования кода.




.deploy_script: &deploy_script
  cache:
    paths:
      - node_modules/
  stage: deployment
  script:
    - yarn run build
    - yarn run deploy
  tags:
    - web-ci

deploy:dev:
  <<: *deploy_script
  variables:
    AWS_S3_HOST_BUCKET_NAME: $AWS_S3_HOST_BUCKET_NAME__DEV
    REACT_APP_API_BASE: $REACT_APP_API_BASE__DEV
  environment:
    name: dev
    url: http://$AWS_S3_HOST_BUCKET_NAME.s3-website.us-east-1.amazonaws.com/
  only:
    - develop


deploy:qa:
  <<: *deploy_script
  when: manual
  variables:
    AWS_S3_HOST_BUCKET_NAME: $AWS_S3_HOST_BUCKET_NAME__QA
    REACT_APP_API_BASE: $REACT_APP_API_BASE__QA
  environment:
    name: qa
    url: http://$AWS_S3_HOST_BUCKET_NAME.s3-website.us-east-1.amazonaws.com/
  only:
    refs:
      - /^vd+.d+.d+$/
    changes:
      - package.json




Строки 95-131 .gitlab-ci.yaml




Обратите внимание, как используются переменные окружения. Команды yarn run build и yarn run deploy используют имена переменных без постфиксов, которые определяются на уровне конкретной джобы из значений, находящихся в переменных с постфиксами.







Рис. 5. Веб-интерфейс гитлаба для управления переменными окружения




На рис. 5 показан веб-интерфейс, в котором можно описать переменные окружения. Они будут доступны внутри пайплайна, когда он запустится. Тут можно определить адреса апи бэкенда, ключи апи для сервисов, которые вы используете: например, Google API key, SSH-ключи для версионирования и другие данные, коммитить которые небезопасно.




Заключение




Даже при рассмотрении CI/CD в рамках специфики фронтенда обнаруживается много деталей и нюансов. Файл конфигурации пайплайнов из моего примера — рабочий, вы можете использовать его для своих проектов, подставив соответствующие npm- или yarn-скрипты. Надеюсь, эта статья станет отправной точкой для дискуссий и погружения в тему.




Источник: http://gs-studio.com/news-about-it/34189-cicd



2023-02-07T14:11:41
DevOps