Запуск проекта в Kubernetes за 60 минут

Kate

Administrator
Команда форума
У Kubernetes высокий порог входа, не все готовы использовать его в своих проектах. Это достаточно сложная для внедрения технология, особенно если конфигурированием кластера заниматься самостоятельно. Но я попробую упростить для вас эту задачу.


Я Павел Селиванов, ведущий DevOps-инженер облачной платформы Mail.ru Cloud Solutions. Я расскажу про альтернативный способ развертывания Kubernetes — использование Managed-варианта от облачного провайдера. Мы запустим реальный API-сервис на примере нашего облака и пройдем основные шаги развертывания приложений в K8s, включая подготовку инфраструктуры, настройку CI/CD-конвейера и всех необходимых объектов Kubernetes: Deployment, Service, Ingress и так далее.


В результате попробуем убедиться, что 60 минут — вполне достаточное время для освоения азов работы с K8s при условии использования его в виде aaS.


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


Практикум в видеоформате можно посмотреть по ссылке.

1. Архитектура проекта​


Архитектурно проект будет максимально простым. Мы развернем в кластере Kubernetes небольшое приложение, написанное на Go и представляющее собой простой API-сервис для работы с пользователями — для их добавления, просмотра, изменения и удаления.


Для приложения заранее подготовлен Dockerfile, обеспечивающий сборку Docker-контейнера. Приложение будет развернуто в кластере Kubernetes в двух инстансах. Однако это количество при необходимости можно изменить.


В качестве бэкенда будем использовать базу данных PostgreSQL, которую запустим в виде aaS в облаке MCS. В базе будут храниться пользователи, добавляемые через приложение.


Для организации доступа к приложению через интернет воспользуемся стандартными абстракциями Kubernetes: Ingress и Service.


Код приложения доступен полностью в GitHub.


rdrnpuodz2iucy9q3i0iguilgyq.jpeg

Архитектура проекта


2. Подготовка инфраструктуры​


Для настройки инфраструктуры необходимо зарегистрироваться на платформе Mail.ru Cloud Solutions, зайти в личный кабинет и последовательно настроить кластер Kubernetes и БД PostgreSQL.


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


Для добавления нового кластера в панели управления облаком MCS необходимо выбрать пункт меню «Контейнеры» — «Кластеры Kubernetes». В открывшейся форме нажать кнопку «Создать кластер».


rw0jmzm2-svcrqiy-fvogi1w5zi.jpeg

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


На первом шаге требуется выбрать конфигурацию кластера (среду) и необходимые сервисы. Среды отличаются параметрами виртуальных машин и отказоустойчивостью: например, для среды Production предусмотрено 3 Master-узла. Для нашего проекта выберем среду Staging. Среди предустановленных сервисов следует обязательно отметить Ingress Controller Nginx.


y19apervchpjavcxjagg89jwor8.jpeg

Выбор конфигурации и предустановленных сервисов на первом шаге создания кластера


На втором шаге указывается имя кластера, параметры Master-узлов и сети. Все значения параметров можно оставить по умолчанию.


4w5q4apjoipqdbvvnjbsmmhpjj4.jpeg

На втором шаге создания кластера оставляем значения по умолчанию


На третьем шаге задаются параметры Node-узлов, а также включается автомасштабирование при необходимости. Укажем количество Node равным 2, остальные параметры можно оставить по умолчанию.


eltvp355qvvgvwqfr6ivloftaku.jpeg

Указание количества Node-узлов на третьем шаге создания кластера


После нажатия на кнопку «Создать кластер» запустится процесс конфигурирования кластера, который может занять 10–20 минут. После его завершения на экране появится информация о созданном кластере, а также можно будет скачать конфигурационный файл kubeconfig. В нем содержатся настройки, необходимые для авторизации в кластере.


Далее необходимо установить клиент kubectl на локальную машину и в переменные окружения экспортировать конфигурационный файл созданного кластера с расширением .yaml следующей командой:


export KUBECONFIG=<путь к файлу kubeconfig>

После этого можно просмотреть узлы, созданные в кластере:


kubectl get no

В ответе увидим три узла: один Master и две ноды, которые будут использоваться для запуска приложения.


hx607mnqf0h04ylnc3pvfwobix0.jpeg



Создание БД PostgreSQL​


Для добавления инстанса БД необходимо в панели управления облаком выбрать пункт меню «Базы данных» и нажать на кнопку «Создать БД» на панели «PostgreSQL».


-hthvzoi_uhtcv2jb-rz1oyfvyq.jpeg

Переход к созданию инстанса БД


На первом шаге можно изменить тип и версию БД — оставляем PostgreSQL версии 12. Из конфигураций выбираем Single — единичный инстанс, подходящий для разработки и тестирования.


9ft8rpyf-lrhqzsdq85f2mwlc4g.jpeg

Выбор типа БД и конфигурации на первом шаге создания инстанса БД


На втором шаге указывается имя инстанса БД, тип виртуальной машины, размер диска и ряд других параметров. Все значения можно оставить по умолчанию, кроме настроек сети: необходимо выбрать ту же виртуальную сеть, что была выбрана (или создана) для кластера Kubernetes. Это нужно для того, чтобы приложения, запущенные в Kubernetes, могли без каких-либо дополнительных настроек получать доступ к инстансу БД.


fimgnrtdayeynrashyodymwzzbq.jpeg

Выбор сети кластера Kubernetes на втором шаге создания инстанса БД


На третьем шаге необходимо указать имя базы данных (по умолчанию совпадает с именем инстанса), логин пользователя (по умолчанию user) и пароль пользователя. Для автоматической генерации пароля можно нажать на кнопку «Сгенерировать».


Так как пароль нам в дальнейшем потребуется, можно заранее скопировать его во временный файл (у нас db-password) с помощью команды:


echo -n <сгенерированный пароль> > db-password

j_klrlhlgbdmtrtjfg7qohwt63u.jpeg

Ввод имени БД, логина и пароля пользователя на третьем шаге создания инстанса БД


После нажатия на кнопку «Создать базу данных» запустится процесс инициализации инстанса БД, который займет несколько минут. После его успешного завершения на экране появится информация о созданном инстансе.


3. Добавление проекта на GitLab​


Следующий шаг — перенос проекта, который был предварительно создан мной на GitHub, в GitLab для дальнейшей настройки конвейера CI/CD. Для начала клонируем проект с GitHub на локальный компьютер. Далее необходимо зарегистрироваться на официальном сайте GitLab и создать новый проект mcs-kubernetes-project с уровнем доступа Private.


9-762pjqwpzfg7mmdv4qsp5jyjs.jpeg

Создание нового проекта в GitLab


Далее клонируем созданный проект на локальную машину командой:


git clone <путь к созданному проекту на GitLab>

При выполнении команды будет показано предупреждение о пустом проекте — это не ошибка.


xnnplth87wmwygaw5lm0hsxfpk8.jpeg



Переходим в созданную папку mcs-kubernetes-project и копируем в нее содержимое директории app из проекта, предварительного загруженного с GitHub:


cd mcs-kubernetes-project
cp -r <локальный путь к проекту, загруженному с GitHub>/app/* .

Применив после этого команду ls -la, должны получить следующий набор файлов:


xfyug89j6ykatpkwwwbbyvtgeuc.jpeg



Остановимся подробнее на Dockerfile. В нем используется двухэтапная сборка (Multi-stage Build). Сначала собирается Go-приложение в одном образе (golang:1.14), в котором есть компилятор Go, все необходимые библиотеки и зависимости. А затем берется полностью пустой образ (scratch), где будет размещен только бинарник приложения. Содержимое Dockerfile приведено ниже:


FROM golang:1.14 as builder
RUN mkdir /app
COPY . /app
WORKDIR /app
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o server .
FROM scratch
ENV PORT=8080
COPY --from=builder /app/server /
EXPOSE 8080
CMD ["/server"]

Закоммитим изменения и запушим их в GitLab. Для этого выполним следующие команды:


git add .
git commit -m "Initial commit"
git push -u origin master

В результате должно обновиться содержимое репозитория на GitLab в разделе «Project information»:


oyqqaeffiosc94bcpshttljwwvs.jpeg

Файлы успешно загружены в репозиторий на GitLab


4. Настройка пайплайна CI/CD​


Настройка CI/CD необходима для того, чтобы максимально сократить количество ручных операций на проекте. Когда разработчик добавляет изменения в код и пушит их в GitLab, репозиторий должен это обнаружить, протестировать и уведомить об ошибках, а в случае отсутствия ошибок выполнить сборку Docker-образа и разместить его в Docker Registry. В качестве Docker Registry будем использовать тот, что встроен в GitLab. На последнем шаге полностью протестированное приложение будет автоматически развернуто в Kubernetes-кластере.


3nm29arfo4-lmilqaiam61__sck.jpeg

Упрощенная схема CI/CD


Для реализации описанного пайплайна необходимо:


  • настроить GitLab Runner, который будет брать задачи из yaml-манифеста и выполнять их;
  • настроить непосредственно сам манифест gitlab-ci.yml.

Установка GitLab Runner​


Недостаток приватных проектов на GitLab в том, что выделяемые им общедоступные раннеры (Shared Runners) ограничены по количеству CI-часов. Поэтому мы не будем использовать раннеры GitLab — создадим свой собственный. Для этого добавим репозиторий с Helm-чартами GitLab, используя следующую команду:


helm repo add gitlab https://charts.gitlab.io

Далее создадим в Kubernetes отдельный namespace — gitlab:


kubectl create namespace gitlab

И затем в рамках созданного namespace установим GitLab Runner. Но предварительно нам потребуется получить для него регистрационный токен на сайте GitLab. Для этого в меню проекта нужно выбрать пункт «Settings» — «CI/CD» и в секции «Runners» нажать на кнопку «Expand»:


audvxcolr_cujlu96maxx1d7tki.jpeg

Переход к параметрам «Runners»


В открывшейся форме необходимо отключить использование Shared runners, сбросив флажок «Enable shared runners for this project», и скопировать регистрационный токен из секции «Specific runners».


h3e9runkq8qp3dg7f2jhosh4ebe.jpeg

Копирование токена и отключение Shared runners


Остается установить Runner при помощи следующей команды, предварительно прописав в параметре runnerRegistrationToken скопированное значение токена:


helm install --namespace gitlab gitlab-runner gitlab/gitlab-runner \
--set rbac.create=true \
--set runners.privileged=true \
--set gitlabUrl=https://gitlab.com/ \
--set runnerRegistrationToken=<скопированный токен из раздела Runners>

Проверить установку Runner можно командой, которая выводит список подов в namespace gitlab:


kubectl get po -n gitlab

Когда в ответе на команду в столбце «READY» появится значение «1/1», раннер будет успешно запущен.


0vqc2akzsm2jajn1xtiwje1-z1a.jpeg



В самом GitLab при этом в разделе «Runners» — «Specific runners» появится информация о добавленном Runner.


6a3tf4qrwytogrddl3a6lyc175i.jpeg

Появление Runner в разделе «Runners» — «Specific runners», доступном после выбора пункта меню «Settings» — «CI/CD»


Настройка yaml-манифеста​


Манифест с описанием пайплайна gitlab-ci.yml необходимо добавить в репозиторий из проекта, предварительного загруженного с GitHub, следующей командой:


cp -r <локальный путь к проекту, загруженному с GitHub>/.gitlab-ci.yml .

Пайплайн CI/CD будет включать три стадии:


  • test — тестирование,
  • build — сборка Docker-образа,
  • deploy — развертывание в Kubernetes.

Остановимся пока на описании первых двух стадий, к деплою вернемся позднее.


На стадии test будет проводиться простой синтаксический анализ кода с помощью команды gofmt. Когда будут обнаружены изменения в коде и CI/CD запустится, GitLab Runner запустит новый контейнер из образа golang:1.14, в котором есть все необходимые утилиты для работы с Go, склонирует туда репозиторий и выполнит необходимое тестирование.


test:
stage: test
image: golang:1.14
script:
- gofmt -e . > /dev/null

На стадии build будет выполняться сборка Docker-образа обновленного приложения. Для этого потребуется Docker daemon, который в манифесте описывается в секции services. GitLab Runner будет запускать новый контейнер из образа docker:19.03.12, а в нем — еще один контейнер для запуска демона, и уже там будет происходить сборка образа приложения. В качестве альтернативы такому способу можно использовать «бездокерные» сборки, предлагаемые в ряде Open Source-решений, например Kaniko.


Секция before_script стадии build описывает действия, которые необходимо выполнить перед сборкой — авторизоваться в Docker Registry. Секция script описывает саму сборку — создание Docker-образа и его отправку в Docker Registry. Каждый новый образ будет создаваться с уникальным именем, состоящим из имени Branch или Tag, для которого происходит сборка (CI_COMMIT_REF_SLUG) и уникального идентификатора пайплайна (CI_PIPELINE_ID).


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


build:
image: docker:19.03.12
stage: build
services:
- docker:19.03.12-dind
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script:
- docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID" .
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID"

После копирования файла gitlab-ci.yml в локальный репозиторий необходимо закоммитить изменения и отправить их в GitLab:


git add .
git commit -m "Add CI"
git push

При переходе в GitLab увидим запуск первого пайплайна.


bduvstrz2zup1edufae-a6w-fvq.jpeg

Запуск пайплайна в GitLab


Чтобы пояснить суть контейнерных сборок, о которых шла речь выше, можно во время выполнения CI/CD запустить команду для просмотра подов в namespace gitlab с использованием ключа -w (означающего бесконечный проcмотр в режиме реального времени):


kubectl get po -n gitlab -w

В выводе команды будут отображаться поды с префиксом «runner-» — это контейнеры, которые создает Gitlab Runner из образов, указанных в манифесте gitlab-ci.yml. Сначала создается контейнер для выполнения тестирования (test), затем для выполнения сборки (build). Впоследствии они уничтожатся.


2n9z4-ntzsy319nw4o5yeoppxpu.jpeg



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


1s5htjj_a2dk2s7i1xojd2gfrig.jpeg

Результат выполнения пайплайна


Созданный на стадии build образ приложения можно посмотреть в GitLab в пункте меню «Packages & Registries» — «Container Registry». Образ можно загрузить на локальный компьютер или развернуть в кластере Kubernetes. Обратите внимание на размер — он будет очень небольшим, всего 4,5 MiB.


qjqtcnqvtwqqjhmpnrrgfcjsf1g.jpeg

Просмотр образа приложения, созданного на стадии «build»


5. Настройка объектов Kubernetes и переменных GitLab, необходимых для деплоя проекта​


Deployment​


Первое, что нужно сделать для развертывания приложения в кластере Kubernetes, — настроить Deployment. Это абстракция Kubernetes, управляющая жизненным циклом приложения и описывающая особенности его запуска: сколько реплик требуется запустить, из какого образа, на каких портах, сколько ресурсов необходимо выделить (RAM, CPU), какие Healthcheck можно использовать для проверки работоспособности, какие метки и селекторы применять и так далее.


h_efqln9j6ayylevy9jbgymedva.jpeg

Deployment


Перейдем к настройке Deployment. Для начала скопируем в локальный репозиторий папку .kube из директории с проектом, загруженным с GitHub:


cp -r <локальный путь к проекту, загруженному с GitHub>/.kube .

Содержимое файла deployment.yaml из папки .kube приведено ниже. Несколько слов о важных параметрах Deployment:


  • replicas — количество реплик приложения, в нашем примере равное 2;
  • progressDeadlineSeconds — максимальный тайм-аут (в секундах), допустимый для развертывания. В нашем примере равен 2 минутам. Если по истечении этого времени будут развернуты не все необходимые поды, будет выполнен автоматический откат к предыдущей версии приложения. Kubernetes по умолчанию реализует Rolling Update: откат произойдет максимально незаметно для пользователя с постепенным переводом пользователей на работоспособные реплики;
  • image — ссылка на образ приложения. Плейсхолдер заменять не нужно: он будет заполняться непосредственно при развертывании, при помощи команды sed. Это самый простой вариант, на практике рекомендуется использовать Helm.
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: mcs-kubernetes-project
    spec:
    replicas: 2
    progressDeadlineSeconds: 120
    selector:
    matchLabels:
    app: mcs-kubernetes-project
    template:
    metadata:
    labels:
    app: mcs-kubernetes-project
    spec:
    imagePullSecrets:
    - name: mcs-kubernetes-project-image-pull
    containers:
    - name: mcs-kubernetes-project
    image: <IMAGE>
    env:
    - name: DB_HOST
    value: <Адрес БД из интерфейса MCS (в нашем примере 10.0.0.13)>
    - name: DB_PORT
    value: "5432"
    - name: DB_USER
    value: "<Логин пользователя БД из интерфейса MCS (в нашем примере user)>"
    - name: DB_PASSWORD
    valueFrom:
    secretKeyRef:
    name: mcs-kubernetes-project
    key: db-password
    - name: DB_NAME
    value: <Имя БД из интерфейса MCS (в нашем примере PostgreSQL-4463)>
    ports:
    - name: http
    containerPort: 8080
    readinessProbe:
    httpGet:
    path: /health
    port: http
    periodSeconds: 10
    initialDelaySeconds: 10

    В файле необходимо вручную прописать ряд параметров.

    Для получения адреса БД, который необходимо прописать в параметре DB_HOST, необходимо вернуться в панель управления облаком MCS и открыть информацию о созданном инстансе БД в пункте меню «Базы данных» — «Инстансы баз данных». Искомый параметр будет отображаться на вкладке «Информация» в поле «Внутренний IP-адрес».
    kgd6v6nw3zisvwkuhkorg6p9e8w.jpeg

    Получение внутреннего IP-адреса инстанса БД — для параметра DB_HOST
    Имя БД, которое необходимо прописать в параметре DB_NAME, можно взять на второй вкладке формы «Список баз данных».
    6yti6d1vwd0cgufje_l2jsx0uag.jpeg

    Получение имени БД — для параметра DB_NAME
    Логин пользователя, который необходимо прописать в параметре DB_USER, указывался нами на этапе создания БД: мы оставили значение по умолчанию user.
    Пароль пользователя БД также был сгенерирован на этапе создания БД, и мы его скопировали в файл db-password. В deployment.yaml пароль БД будет браться из секрета, который нам необходимо создать. Секреты в Kubernetes предназначены для хранения конфиденциальной информации.
    Создадим новый namespace mcs-kubernetes-project:
    kubectl create ns mcs-kubernetes-project

    И в рамках него добавим секрет с ключом db-password и типом generic на основе созданного ранее файла следующей командой:
    kubectl create secret generic mcs-kubernetes-project \
    -n mcs-kubernetes-project \
    --from-file db-password

    В качестве ключа секрета в этом случае выступит имя файла, в качестве значения — его содержимое. Если вы не создавали файл, а просто скопировали пароль, секрет можно добавить другой командой:
    kubectl create secret generic mcs-kubernetes-project \
    -n mcs-kubernetes-project \
    --from-literal db-password=<сохраненный ранее пароль от БД>

    Чтобы убедиться в создании секрета, выполним команду:
    kubectl get secrets -n mcs-kubernetes-project

    Секрет был успешно добавлен.
    fv-65qeu9ddjulkmza_y3skysw8.jpeg

    Service​

    Это абстракция, необходимая для организации сетевого доступа и балансировки внутри кластера Kubernetes. При этом Service не является Proxy в чистом виде: никакого контейнера, виртуальной машины или иного объекта не создается. Это «виртуальный» балансировщик на основе iptables либо виртуальных IP-адресов Linux. Он конфигурирует кластер Kubernetes таким образом, чтобы могла осуществляться балансировка, и предоставляет следующее:
    • имя, по которому можно обращаться к сервису внутри кластера;
    • IP-адрес, в который будет преобразовываться имя с помощью внутреннего DNS Kubernetes;
    • номер порта.
    • Предположим, внутри кластера есть сервис A, которому нужно обратиться к сервису B с несколькими инстансами. Число инстансов и их расположение не имеют значения: достаточно знать имя сервиса B и выполнить запрос по этому имени. Благодаря Service трафик будет автоматически распределен между инстансами.
    596eep1fzztzxdgpco0x20zmwzs.jpeg

    Service
    Манифест service.yaml находится в той же папке, что и deployment.yaml — .kube. Содержимое файла ниже.
    apiVersion: v1
    kind: Service
    metadata:
    name: mcs-kubernetes-project
    spec:
    selector:
    app: mcs-kubernetes-project
    ports:
    - name: http
    targetPort: http
    port: 80

    Здесь мы задаем имя сервису mcs-kubernetes-project, по которому можно будет обращаться к подам внутри кластера с нашим API-сервисом. Для сервиса будет открываться 80 порт, который ведет на порт внутри пода с названием http.

    Ingress​

    Так как Service предназначен для распределения трафика только внутри кластера Kubernetes, для организации доступа извне необходимо использовать Ingress. Это балансировщик, умеющий работать с HTTP. В настройках Ingress можно указать, на какие поды (относящиеся к какому внутреннему Service) необходимо направлять внешний трафик, приходящий с указанных адресов.
    lgiq4kypcvobekvulewaknxhxyi.jpeg

    Ingress
    Содержимое Ingress.yaml из папки .kube приведено ниже.
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: mcs-kubernetes-project
    spec:
    rules:
    - http:
    paths:
    - path: /
    pathType: Prefix
    backend:
    service:
    name: mcs-kubernetes-project
    port:
    name: http

    Объекту Ingress мы присваиваем имя mcs-kubernetes-project. Каких-либо ограничений на хосты нет: все, что придет извне в кластер в корневой url или любой другой, будет направлено на Service с именем mcs-kubernetes-project.
    При этом Ingress Controller, который будет отвечать за обработку внешнего трафика, был создан автоматически при запуске кластера — в рамках namespace ingress-nginx. Чтобы убедиться в этом, можно выполнить команду:
    kubectl get po -n ingress-nginx

    -wal--nylveou93uqslmmo7zk6y.jpeg

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

    RBAC и настройка доступов между GitLab и Kubernetes​

    Чтобы GitLab Runner мог деплоить приложение в кластер Kubernetes, необходимо дать ему соответствующие права внутри конкретного namespace. Для этого потребуется создать несколько RBAC-объектов:
    • создать сервисную учетную запись (УЗ) командой:
      kubectl create sa deploy -n mcs-kubernetes-project
    • предоставить ей права на создание объектов внутри namespace mcs-kubernetes-project:
      kubectl create rolebinding deploy \
      -n mcs-kubernetes-project \
      --clusterrole edit \
      --serviceaccount mcs-kubernetes-project:deploy
    • Токен созданной УЗ необходимо прописать в GitLab-переменных. С помощью этого токена GitLab Runner сможет получать доступ к кластеру Kubernetes. Для получения токена воспользуйтесь командой:
    kubectl get secret -n mcs-kubernetes-project \
    $(kubectl get sa -n mcs-kubernetes-project deploy \
    -o jsonpath='{.secrets[].name}') \
    -o jsonpath='{.data.token}'

    Скопируйте токен в буфер обмена и вернитесь в интерфейс GitLab. В пункте меню «Settings» — «CI/CD» нужно нажать на кнопку «Expand» в секции «Variables» и затем на кнопку «Add variable».
    a-xb4wvecz6nku4ebchzobps6ey.jpeg

    Раскрытие раздела «Variables» в пункте меню «Settings» — «CI/CD»
    1tshqnll37k--bg6wjdha_scxcc.jpeg

    Переход к добавлению новой переменной в разделе «Variables»
    В открывшейся форме требуется указать имя переменной, которое будет впоследствии использоваться в секции deploy манифеста gitlab-ci.yml — K8S_CI_TOKEN. В качестве значения переменной нужно использовать скопированный ранее токен сервисной УЗ. Также следует снять флажок «Protect variable», который разрешает доступ к переменным исключительно из ветки master. И нужно установить флажок «Mask variable» — в таком случае переменная будет закрытой, то есть ее значение не будет отображаться внутри логов CI/CD.
    damzpian52e6akakdyryjlptaqe.jpeg

    Добавление переменной K8S_CI_TOKEN
    Последнее, что необходимо сделать перед запуском деплоя, — добавить в Kubernetes возможность авторизации в GitLab, чтобы получать из Docker Registry формируемый образ и запускать на его основе приложение. Для этого нужно добавить Deploy token.
    В GitLab необходимо выбрать пункт меню «Repository» и нажать на кнопку «Expand» в секции «Deploy tokens».
    o_uwl31vtk48cfdkvrlznondwhu.jpeg

    Переход к добавлению Deploy token
    В открывшейся форме необходимо ввести имя токена k8s-pull-token и установить флажок «read_registry», который будет означать доступ к образам только на чтение.
    y8quxtmeehhdrmadow-ae7f1k_o.jpeg

    Добавление Deploy token
    После нажатия на кнопку «Create deploy token» на экране появится информация с именем пользователя и паролем для нового токена.
    6cytj2qulkx9mf31knqp-v8djrw.jpeg

    Вывод имени пользователя и пароля после добавления Deploy token в GitLab
    Сформированные имя пользователя и пароль нужно скопировать в следующую команду, после чего выполнить ее в консоли. Команда добавит секрет с типом docker-registry и именем mcs-kubernetes-project-image-pull. С помощью секрета Kubernetes сможет получать формируемые образы из GitLab.
    kubectl create secret docker-registry mcs-kubernetes-project-image-pull \
    --docker-server registry.gitlab.com \
    --docker-email 'admin@mycompany.com' \
    --docker-username '<первая строчка (имя пользователя) из окна создания токена в GitLab>' \
    --docker-password '<вторая строчка (пароль) из окна создания токена в GitLab>' \
    --namespace mcs-kubernetes-project

    6. Деплой проекта​

    Перед деплоем выполним коммит последних изменений и отправим их в GitLab:
    git add .kube
    git commit -m "Add Kubernetes manifests"
    git push

    После этого пайплайн повторно запустится в GitLab и на этот раз завершится успешно.
    otcrslfjgyhgoab2qshfj6brqja.jpeg

    Успешное завершение пайплайна в GitLab
    Рассмотрим подробнее стадию deploy в файле gitlab-ci.yml. За основу берется образ bitnami/kubectl:1.20, в котором есть предустановленный kubectl.
    В секции before_script происходит подключение GitLab Runner к кластеру Kubernetes при помощи токена сервисной УЗ, который мы прописывали в переменной K8S_CI_TOKEN.
    В секции script описана непосредственно установка приложения. При помощи sed идет замена плейсхолдера в файле deployment.yaml на образ приложения, собранный на стадии build. Далее при помощи команды apply к кластеру Kubernetes применяются все изменения из манифестов папки .kube. И после этого происходит развертывание полученного образа. Команда rollout status позволяет отслеживать его статус. Если за указанный в настройках тайм-аут (2 минуты, про которые мы говорили выше) деплой не будет завершен, будет выполнен автоматический откат к предыдущей версии при помощи команды rollout undo.
    deploy:
    stage: deploy
    image: bitnami/kubectl:1.20
    variables:
    K8S_NAMESPACE: mcs-kubernetes-project
    before_script:
    # Set kubernetes credentials
    - export KUBECONFIG=/tmp/kubeconfig
    - kubectl config set-cluster k8s --insecure-skip-tls-verify=true --server=https://kubernetes.default
    - kubectl config set-credentials ci --token="$(echo $K8S_CI_TOKEN | base64 -d)"
    - kubectl config set-context ci --cluster=k8s --user=ci --namespace $K8S_NAMESPACE
    - kubectl config use-context ci
    script:
    - sed -i -e "s,<IMAGE>,$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID,g" .kube/deployment.yaml
    - kubectl apply -f .kube
    - kubectl rollout status deployment/mcs-kubernetes-project ||
    (kubectl rollout undo deployment/mcs-kubernetes-project && exit 1)

    Чтобы убедиться, что развертывание произошло успешно, достаточно выполнить несколько простых команд в namespace mcs-kubernetes-project:
    • вывод подов, который покажет 2 реплики приложения:
      kubectl get po -n mcs-kubernetes-project

      w8i1cpaqtzj4zz_wulrjzbefzc8.jpeg
    • вывод Service:
      kubectl get svc -n mcs-kubernetes-project

      dhd3tpq58gt9kyu74iielm28ntg.jpeg
    • вывод Ingress:
      kubectl get ing -n mcs-kubernetes-project

      etbqennp75lwmipq3wckli-_z6y.jpeg
    • Чтобы проверить работоспособность развернутого приложения, необходимо получить IP-адрес, по которому кластер Kubernetes доступен извне. Для просмотра этого адреса выполним команду:
    kubectl get svc -n ingress-nginx

    В результатах команды будут показаны сервисы, автоматически созданные при добавлении Ingress Controller. Среди них сервис с типом LoadBalancer. IP-адрес, указанный для него в столбце «EXTERNAL-IP», и есть искомый адрес для доступа к кластеру, который можно прописать в DNS или использовать напрямую для обращения к нашему приложению.
    rjscxm_hw88pymvah9l5r23n4iw.jpeg

    Для вывода только внешнего IP-адреса можно воспользоваться расширенным вариантом команды:
    kubectl get svc -n ingress-nginx nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[].ip}'

    Используя этот адрес, проверим работу нашего API-сервиса. Сначала добавим пользователя:
    curl -k https://<INGRESS IP>/users -X POST -H "Content-Type: application/json" --data '{"name":"test","location":"asdf","age":12}'

    В ответе получим сообщение об успешном добавлении.
    fqrtolv7eglqm3g7ly03d2edsac.jpeg

    И затем получим список всех пользователей с помощью команды:
    curl -k https://<INGRESS IP>/users

    В ответе увидим добавленного пользователя.
    _fqly-3kqcdrtxj12dg8vszcfns.jpeg

    Таким образом, приложение работает. Пользователи успешно добавляются и извлекаются из БД PostgreSQL.

    Выводы: чему мы научились за 60 минут​

    Мы рассмотрели основные шаги для развертывания Cloud Native-приложения в Kubernetes-кластере. Выбрали архитектуру и последовательно добавили необходимые компоненты: кластер K8s, DBaaS PostgreSQL, репозиторий кода в GitLab. Настроили GitLab Runner, пайплайн CI/CD и все необходимые для деплоя приложения объекты Kubernetes: Deployment, Service и Ingress. Добавили ряд переменных и токенов, чтобы Kubernetes и GitLab могли общаться друг с другом, поработав немного с RBAC и секретами. В результате получили работоспособное отказоустойчивое приложение, сборка и развертывание которого осуществляются автоматически.
    Разумеется, за 60 минут мы не могли охватить все аспекты работы с Kubernetes. Но выяснили, что этого времени достаточно для запуска первого приложения в кластере K8s.
    Тут можно почитать, как устроен Kubernetes aaS на платформе Mail.ru Cloud Solutions: что у него под капотом и что в него еще входит, кроме собственно Kubernetes.

    Если захотите сами повторить то, что описано в этой статье, можете подключить Kubernetes as a Service здесь. Новые пользователи получают 3000 бонусов для тестирования, и этого более чем достаточно, чтобы попробовать всё, что описано в этой статье. В технической поддержке нужно будет дополнительно попросить поднять квоты: 4 инстанса, 5 CPU, 10 ГБ RAM, 5 дисков, два IP-адреса.
    Описанный сценарий не обязательно повторять в облаке: при развертывании On-premise шаги будут примерно те же, но дольше и сложнее. Managed-решения значительно сокращают время конфигурирования кластера, делая работу с ним по-настоящему быстрой и удобной, особенно для новых пользователей.

Источник статьи: https://habr.com/ru/company/mailru/blog/565250/
 
Сверху