Шаг за шагом! Руководство по непрерывному развертыванию Kubernetes

Kubernetes
Шаг за шагом! Руководство по непрерывному развертыванию Kubernetes

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

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

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

В итоге мы это сделали, хоть и далеко от отведенной недели — на создание трех кластеров, включая их dev, test и production, у нас ушел почти месяц.

В этой статье я подробно расскажу, как развернуть приложение в Kubernetes. После прочтения этой статьи у вас будет эффективное развертывание Kubernetes и рабочий процесс непрерывной доставки.

Непрерывная интеграция и доставка

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

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

Мы будем использовать Semaphore, быструю, мощную и простую в использовании платформу непрерывной интеграции и доставки (CI/CD), которая автоматизирует все процессы:

1. Установите зависимости проекта

2. Запустите модульные тесты

3. Создайте образ Docker

4. Отправьте образ в Docker Hub.

5. Развертывание Kubernetes в один клик

Для приложения у нас есть микросервис Ruby Sinatra, который предоставляет некоторые конечные точки HTTP. В проекте уже есть все необходимое для развертывания, но некоторые компоненты все еще необходимы.


Готов к работе


Прежде чем начать, вам необходимо войти в свои учетные записи Github и Semaphore. Кроме того, чтобы облегчить извлечение или отправку образов Docker позже, вам необходимо войти в Docker Hub.

Далее вам нужно установить некоторые инструменты на свой компьютер:

  • Git: работа с кодом
  • curl: швейцарский армейский нож сетевого взаимодействия
  • kubectl: удаленно управляйте своим кластером

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

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

С этого мы уже можем начать. Первое, что нужно сделать, это разветвить репозиторий.


Форк-репозиторий


Разветвите демонстрационное приложение, которое мы будем использовать в этом посте.

  1. Посетите репозиторий semaphore-demo-ruby-kubernetes и щелкните в правом верхнем углу.Forkкнопка
  2. нажмитеClone or downloadкнопку и скопируйте адрес
  3. Скопируйте репозиторий: $ git clone https://github.com/ваш_репозиторий_путь…

Подключить новый репозиторий с помощью Semaphore

1. Войдите в свой семафор

2. Щелкните ссылку на боковой панели, чтобы создать новый проект.

3. Нажмите рядом с вашим репозиторием [Add Repository] кнопка

Тест с семафором


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

Откройте исходный файл конвейера, расположенный по адресу .semaphore/semaphore.yml, и быстро просмотрите его. Этот конвейер описывает все шаги, которые Semaphore должен выполнить для создания и тестирования приложения. Он начинается с версии и имени.

version: v1.0
name: CI

Далее идет агент, представляющий собой виртуальную машину, на которой выполняется задание. Мы можем выбрать из 3 типов:

agent:
  machine:
    type: e1-standard-2
    os_image: ubuntu1804

Блоки, задачи и задания определяют операции, которые должны выполняться на каждом этапе конвейера. В Semaphore блоки выполняются последовательно, и в то же время задания в блоках выполняются параллельно. Конвейер содержит 2 блока: один для установки библиотеки и один для запуска тестов.

Первый блок загружает и устанавливает драгоценные камни Ruby.

- name: Install dependencies
  task:
    jobs:
      - name: bundle install
        commands:
          - checkout
          - cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH,gems-master
          - bundle install --deployment --path .bundle
          - cache store gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock) .bundle

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

blocks:
  - name: Install dependencies
    task:
      jobs:
        - name: bundle install
          commands:
            - checkout
            - cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH,gems-master
            - bundle install --deployment --path .bundle
            - cache store gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock) .bundle

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

- name: Tests
  task:
    jobs:
      - name: rspec
        commands:
          - checkout
          - cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH,gems-master
          - bundle install --deployment --path .bundle
          - bundle exec rspec

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

promotions:
  - name: Dockerize
    pipeline_file: docker-build.yml
    auto_promote_on:
      - result: passed

Рабочий процесс продолжается со следующим конвейером.


Создайте образ Docker


Мы можем запустить что угодно в Kubernetes, если оно упаковано в образ Docker. В этой части мы научимся создавать образ.

Наш образ Docker будет содержать код приложения, Ruby и все библиотеки. Давайте сначала посмотрим на Dockerfile:

FROM ruby:2.5
 
RUN apt-get update -qq && apt-get install -y build-essential
 
ENV APP_HOME /app
RUN mkdir $APP_HOME
WORKDIR $APP_HOME
 
ADD Gemfile* $APP_HOME/
RUN bundle install --without development test
 
ADD . $APP_HOME
 
EXPOSE 4567
 
CMD ["bundle", "exec", "rackup", "--host", "0.0.0.0", "-p", "4567"]

DockerFile похож на подробный рецепт, содержащий все шаги и команды, необходимые для создания изображения контейнера:

1. Начните с готового образа ruby

2. Установите инструменты сборки с помощью apt-get

3. Скопируйте Gemfile, так как в нем есть все зависимости

4. Установите их с помощью пакетов

5. Скопируйте исходный код приложения

6. Определите порт прослушивания и команду запуска

Мы запечем наш рабочий образ в среде Semaphore. Однако, если вы хотите провести быстрый тест на своем компьютере, введите:

$ docker build . -t test-image

Запустите с Docker и откройте внутренний порт 4567 для локального запуска сервера:

$ docker run -p 4567:4567 test-image

Теперь вы можете протестировать доступную конечную точку HTTP:

$ curl -w "\n" localhost:4567
hello world :))

Добавьте учетную запись Docker Hub в Semaphore


Semaphore имеет безопасный механизм для хранения конфиденциальной информации, такой как пароли, токены или ключи. Чтобы иметь возможность отправлять изображения в реестр Docker Hub, вам необходимо создать секрет с вашим именем пользователя и паролем:

  1. Откройте свой семафор
  2. На левой панели навигации нажмите [Secret
  3. Нажмите【Creat New Secret
  4. Имя секрета должно быть Dockerhub, введите данные для входа (как показано на изображении ниже) и сохраните их.

Создание конвейера Docker


Конвейер начинает сборку и отправляет образ в Docker Hub, у него всего 1 блок и 1 задание:

На этот раз нам нужно использовать более высокую производительность, поскольку Docker имеет тенденцию быть более ресурсоемким. Мы выбираем машину среднего уровня e1-standard-4 с четырьмя процессорами, 8 ГБ ОЗУ и 35 ГБ дискового пространства:

version: v1.0
name: Docker build
agent:
  machine:
    type: e1-standard-4
    os_image: ubuntu1804

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

Следующая команда — docker pull, которая пытается получить последний образ. Если образ найден, Docker может повторно использовать некоторые из этих слоев, чтобы ускорить процесс сборки. Не беспокойтесь, если у вас нет последней версии образа, просто сборка займет немного больше времени.

Наконец, мы нажимаем новое изображение. Обратите внимание, что здесь мы используем переменную SEMAPHORE_WORKFLOW_ID, чтобы пометить зеркало.

blocks:
  - name: Build
    task:
      secrets:
        - name: dockerhub
      jobs:
      - name: Docker build
        commands:
          - echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
          - checkout
          - docker pull "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:latest || true
          - docker build --cache-from "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:latest -t "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID .
          - docker images
          - docker push "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID

Когда изображение готово, мы вступаем в фазу сдачи проекта. Мы расширим наш конвейер Semaphore за счет ручного продвижения.

promotions:
  - name: Deploy to Kubernetes
    pipeline_file: deploy-k8s.yml

Чтобы выполнить первую автоматическую сборку, выполните push:

$ touch test-build
$ git add test-build
$ git commit -m "initial run on Semaphore“
$ git push origin master

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

Развертывание в Kubernetes


Автоматическое развертывание — сильная сторона Kubernetes. Что нам нужно сделать, так это сообщить кластеру наши окончательные ожидания, а за все остальное он будет нести ответственность.

Однако перед развертыванием необходимо загрузить файл kubeconfig в Semaphore.


Загрузить Kubeconfig в Semaphore


Нам нужен второй секрет: kubeconfig кластера. Этот файл предоставляет административный доступ к нему. Поэтому мы не хотим проверять файлы в репозиторий.

Создайте секрет с именем do-k8s и загрузите файл kubeconfig в /home/semaphore/.kube/dok8s.yaml:

Контрольный список развертывания

Хотя Kubernetes уже является платформой для оркестровки контейнеров, мы не управляем контейнерами напрямую. Фактически, самая маленькая единица развертывания — это модуль. Стая похожа на группу неразлучных друзей, всегда вместе идущих в одно и то же место. Поэтому убедитесь, что контейнеры в модуле работают на одном узле и имеют один и тот же IP-адрес. Их можно запускать и останавливать синхронно, а поскольку они работают на одной машине, они могут совместно использовать ресурсы.

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

Откройте файл, расположенный по адресу deploymente.yml. Вот манифест для развертывания нашего приложения, которое разделено на два ресурса тремя черточками. Сначала разверните ресурсы:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: semaphore-demo-ruby-kubernetes
spec:
  replicas: 1
  selector:
    matchLabels:
      app: semaphore-demo-ruby-kubernetes
  template:
    metadata:
      labels:
        app: semaphore-demo-ruby-kubernetes
    spec:
      containers:
        - name: semaphore-demo-ruby-kubernetes
          image: $DOCKER_USERNAME/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID

Вот несколько понятий для пояснения:

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


Второй ресурс — сервис. Он привязывается к порту 80 и перенаправляет HTTP-трафик на модули в развертывании:

---
 
apiVersion: v1
kind: Service
metadata:
  name: semaphore-demo-ruby-kubernetes-lb
spec:
  selector:
    app: semaphore-demo-ruby-kubernetes
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 4567

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

Конвейер развертывания


Сейчас мы переходим к заключительному этапу настройки CI/CD. На данный момент у нас есть конвейер CI, определенный в semaphore.yml, и конвейер Docker, определенный в docker-build.yml. На этом этапе мы выполним развертывание в Kubernetes.

Откройте конвейер развертывания в .semaphore/deploy-k8s.yml:

version: v1.0
name: Deploy to Kubernetes
agent:
  machine:
    type: e1-standard-2
    os_image: ubuntu1804

Два задания образуют конечный конвейер:

Задание 1 начинает развертываться. После импорта файла kubeconfig envsubst заменяет переменные-заполнители в deployment.yaml их фактическими значениями. Затем kubectl apply отправляет манифест в кластер.

blocks:
  - name: Deploy to Kubernetes
    task:
      secrets:
        - name: do-k8s
        - name: dockerhub
 
      env_vars:
        - name: KUBECONFIG
          value: /home/semaphore/.kube/dok8s.yaml
 
      jobs:
      - name: Deploy
        commands:
          - checkout
          - kubectl get nodes
          - kubectl get pods
          - envsubst < deployment.yml | tee deployment.yml
          - kubectl apply -f deployment.yml

Задание 2 помечает образ как актуальный, чтобы мы могли использовать его в качестве кэша при следующем запуске.

- name: Tag latest release
  task:
    secrets:
      - name: dockerhub
    jobs:
    - name: docker tag latest
      commands:
        - echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
        - docker pull "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID
        - docker tag "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:latest
        - docker push "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:latest

Это последний шаг в рабочем процессе.


Развернуть приложение

Давайте научим наше приложение Sinatra петь. Добавьте следующий код в класс App в app.rb:

get "/sing" do
  "And now, the end is near
   And so I face the final curtain..."
end

Отправьте измененный файл на Github:

$ git add .semaphore/*
$ git add deployment.yml
$ git add app.rb
$ git commit -m "test deployment”
$ git push origin master

Подождите, пока конвейер сборки докера завершится, и вы сможете просмотреть ход работы Semaphore:

Пришло время развернуть, нажмитеPromoteкнопку, чтобы проверить, работает ли она:

У нас хорошее начало, теперь пришло время взглянуть на Kubernetes. Мы можем проверить статус развертывания с помощью kubectl, начальное состояние — три обязательных модуля и ноль доступных:

$ kubectl get deployments
NAME                             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
semaphore-demo-ruby-kubernetes   3         0         0            0           15m

Через несколько секунд pod запустился и согласование завершилось:

$ kubectl get deployments
NAME                             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
semaphore-demo-ruby-kubernetes   3         3         3            3           15m

Используйте get all, чтобы получить общее состояние кластера, в котором показаны модули, службы, развертывания и реплики:

$ kubectl get all
NAME                                                  READY   STATUS    RESTARTS   AGE
pod/semaphore-demo-ruby-kubernetes-7d985f8b7c-454dh   1/1     Running   0          2m
pod/semaphore-demo-ruby-kubernetes-7d985f8b7c-4pdqp   1/1     Running   0          119s
pod/semaphore-demo-ruby-kubernetes-7d985f8b7c-9wsgk   1/1     Running   0          2m34s
 
 
NAME                                        TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)        AGE
service/kubernetes                          ClusterIP      10.12.0.1              443/TCP        24m
service/semaphore-demo-ruby-kubernetes-lb   LoadBalancer   10.12.15.50   35.232.70.45   80:31354/TCP   17m
 
 
NAME                                             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/semaphore-demo-ruby-kubernetes   3         3         3            3           17m
 
NAME                                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/semaphore-demo-ruby-kubernetes-7d985f8b7c   3         3         3       2m3

IP-адрес службы отображается после модуля. У меня балансировщик нагрузки был назначен на внешний IP 35.232.70.45. Его нужно сменить на тот, который вам назначил ваш провайдер, тогда давайте опробуем новый сервер.

$ curl -w "\n" http://YOUR_EXTERNAL_IP/sing

Теперь конец не за горами.

Победа близка


Развертывание в Kubernetes не так сложно, если у вас есть правильное решение CI/CD. Теперь у вас есть полностью автоматизированный конвейер непрерывной доставки для Kubernetes.

Вот несколько предложений по разветвлению и экспериментам с semaphore-demo-ruby-kubernetes в Kubernetes по желанию:

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