Дипломный практикум в Yandex.Cloud - Леонид Хорошев
- Цели:
- Этапы выполнения:
- Что необходимо для сдачи задания?
- Как правильно задавать вопросы дипломному руководителю?
Перед началом работы над дипломным заданием изучите Инструкция по экономии облачных ресурсов.
Цели:
- Подготовить облачную инфраструктуру на базе облачного провайдера Яндекс.Облако.
- Запустить и сконфигурировать Kubernetes кластер.
- Установить и настроить систему мониторинга.
- Настроить и автоматизировать сборку тестового приложения с использованием Docker-контейнеров.
- Настроить CI для автоматической сборки и тестирования.
- Настроить CD для автоматического развёртывания приложения.
Этапы выполнения:
Создание облачной инфраструктуры
Для начала необходимо подготовить облачную инфраструктуру в ЯО при помощи Terraform.
Особенности выполнения:
- Бюджет купона ограничен, что следует иметь в виду при проектировании инфраструктуры и использовании ресурсов; Для облачного k8s используйте региональный мастер(неотказоустойчивый). Для self-hosted k8s минимизируйте ресурсы ВМ и долю ЦПУ. В обоих вариантах используйте прерываемые ВМ для worker nodes.
Предварительная подготовка к установке и запуску Kubernetes кластера.
- Создайте сервисный аккаунт, который будет в дальнейшем использоваться Terraform для работы с инфраструктурой с необходимыми и достаточными правами. Не стоит использовать права суперпользователя
resource "yandex_iam_service_account" "sa" {
name = var.sa_name
}
Добавляем права storage.admin
, необходимые для создания и работы с бакетом
resource "yandex_resourcemanager_folder_iam_member" "sa-admin" {
folder_id = var.folder_id
role = "storage.admin"
member = "serviceAccount:${yandex_iam_service_account.sa.id}"
}
Создаем ключ доступа к нашему хранилищу
resource "yandex_iam_service_account_static_access_key" "sa-static-key" {
service_account_id = yandex_iam_service_account.sa.id
description = "static access key for object storage"
}
Также, чтобы получить ключ доступа и привытный ключ, суонфигурированный вышеуказанным кодом - подготовит возможность вывода значений ключей в терминал, для чего создадим файл outputs.tf
output "s3_access_key" {
description = "Yandex Cloud S3 access key"
value = yandex_iam_service_account_static_access_key.sa-static-key.access_key
sensitive = true
}
output "s3_secret_key" {
description = "Yandex Cloud S3 secret key"
value = yandex_iam_service_account_static_access_key.sa-static-key.secret_key
sensitive = true
- Подготовьте backend для Terraform:
а. Рекомендуемый вариант: S3 bucket в созданном ЯО аккаунте(создание бакета через TF) б. Альтернативный вариант: Terraform Cloud
Применяем изменения и узнаем значения ключей
terraform plan
terraform apply
terraform output s3_access_key
terraform output s3_secret_key
Далее прописываем их значение в конфигурации s3 backend
в файле providers.tf
(примечание - в момент создания бакета нижеприведенный блок кода по инициализации s3 backend
закомментирован, так как нельзя настроить удаленное хранение состояния конфигурации терраформ в бакете, не создав при этом сам бакет).
backend "s3" {
endpoints = {
s3 = "https://storage.yandexcloud.net"
}
bucket = "diplom-project-khoroshevlv"
region = "ru-central1"
key = "terraform.tfstate"
access_key = <my access_key>
secret_key = <my access_key>
skip_region_validation = true
skip_credentials_validation = true
skip_requesting_account_id = true
skip_s3_checksum = true
}
}
Инициализируем инфраструктуру
terraform init
- Создайте VPC с подсетями в разных зонах доступности.
resource "yandex_vpc_network" "my_vpc" {
name = var.VPC_name
}
resource "yandex_vpc_subnet" "public_subnet" {
count = length(var.public_subnet_zones)
name = "${var.public_subnet_name}-${var.public_subnet_zones[count.index]}"
v4_cidr_blocks = [
cidrsubnet(var.public_v4_cidr_blocks[0], 4, count.index)
]
zone = var.public_subnet_zones[count.index]
network_id = yandex_vpc_network.my_vpc.id
}
К терраформ коду указываем следующие переменные:
### vpc vars
variable "VPC_name" {
type = string
default = "my-vpc"
}
### subnet vars
variable "public_subnet_name" {
type = string
default = "public"
}
variable "public_v4_cidr_blocks" {
type = list(string)
default = ["192.168.10.0/24"]
}
variable "subnet_zone" {
type = string
default = "ru-central1"
}
variable "public_subnet_zones" {
type = list(string)
default = ["ru-central1-a", "ru-central1-b", "ru-central1-d"]
}
- Убедитесь, что теперь вы можете выполнить команды
terraform destroy
иterraform apply
без дополнительных ручных действий.
При выполнении команды terraform destroy
удаляются все вычислительные ресурсы, кроме нашего бакета и загруженного в него terraform.tfstate
, а также созданной нами сети my-vpc
(лжидаемый результат).
Применяем изменения и проверяем инфраструктуру
terraform apply
terraform state list
- В случае использования Terraform Cloud в качестве backend убедитесь, что применение изменений успешно проходит, используя web-интерфейс Terraform cloud.
Ожидаемые результаты:
- Terraform сконфигурирован и создание инфраструктуры посредством Terraform возможно без дополнительных ручных действий.
- Полученная конфигурация инфраструктуры является предварительной, поэтому в ходе дальнейшего выполнения задания возможны изменения.
Создание Kubernetes кластера
На этом этапе необходимо создать Kubernetes кластер на базе предварительно созданной инфраструктуры. Требуется обеспечить доступ к ресурсам из Интернета.
Это можно сделать двумя способами:
- Рекомендуемый вариант: самостоятельная установка Kubernetes кластера.
а. При помощи Terraform подготовить как минимум 3 виртуальных машины Compute Cloud для создания Kubernetes-кластера. Тип виртуальной машины следует выбрать самостоятельно с учётом требовании к производительности и стоимости. Если в дальнейшем поймете, что необходимо сменить тип инстанса, используйте Terraform для внесения изменений.
В целях экономии выделенного бюджета и с учетом ресурсоемкости создадим кластер из одной control-plane
ноды и двух worker
нод.
Конфиграция control-plane
ноды:
resource "yandex_compute_instance" "control-plane" {
name = var.control_plane_name
platform_id = var.platform
resources {
cores = var.control_plane_core
memory = var.control_plane_memory
core_fraction = var.control_plane_core_fraction
}
boot_disk {
initialize_params {
image_id = var.image_id
size = var.control_plane_disk_size
}
}
scheduling_policy {
preemptible = var.scheduling_policy
}
network_interface {
subnet_id = yandex_vpc_subnet.public_subnet[0].id
nat = var.nat
}
metadata = {
user-data = "${file("/home/leo/kuber-homeworks/3.2/terraform/cloud-init.yaml")}"
}
}
Переменные:
### control-plane node vars
variable "control_plane_name" {
type = string
default = "control-plane"
}
variable "platform" {
type = string
default = "standard-v1"
}
variable "control_plane_core" {
type = number
default = "4"
}
variable "control_plane_memory" {
type = number
default = "8"
}
variable "control_plane_core_fraction" {
description = "guaranteed vCPU, for yandex cloud - 20, 50 or 100 "
type = number
default = "20"
}
variable "control_plane_disk_size" {
type = number
default = "50"
}
variable "image_id" {
type = string
default = "fd893ak78u3rh37q3ekn"
}
variable "scheduling_policy" {
type = bool
default = "true"
}
Конфигурация worker
нод:
resource "yandex_compute_instance" "worker" {
count = var.worker_count
name = "worker-node-${count.index + 1}"
platform_id = var.worker_platform
zone = var.public_subnet_zones[count.index]
resources {
cores = var.worker_cores
memory = var.worker_memory
core_fraction = var.worker_core_fraction
}
boot_disk {
initialize_params {
image_id = var.image_id
size = var.worker_disk_size
}
}
scheduling_policy {
preemptible = var.scheduling_policy
}
network_interface {
subnet_id = yandex_vpc_subnet.public_subnet[count.index].id
nat = var.nat
}
metadata = {
user-data = "${file("/home/leo/diplom/terraform/cloud-init.yaml")}"
}
}
Переменные:
### worker nodes vars
variable "worker_count" {
type = number
default = "2"
}
variable "worker_platform" {
type = string
default = "standard-v1"
}
variable "worker_cores" {
type = number
default = "4"
}
variable "worker_memory" {
type = number
default = "2"
}
variable "worker_core_fraction" {
description = "guaranteed vCPU, for yandex cloud - 20, 50 or 100 "
type = number
default = "20"
}
variable "worker_disk_size" {
type = number
default = "50"
}
variable "nat" {
type = bool
default = "true"
}
Для всех виртуальных машин используется cloud-init.yaml
следующей конфигурации:
#cloud-config
users:
- name: leo
ssh_authorized_keys:
- ssh-rsa <public_key>
sudo: ['ALL=(ALL) NOPASSWD:ALL']
groups: sudo
shell: /bin/bash
package_update: true
package_upgrade: true
packages:
- nginx
- nano
- software-properties-common
runcmd:
- mkdir -p /home/leo/.ssh
- chown -R leo:leo /home/leo/.ssh
- chmod 700 /home/leo/.ssh
- sudo add-apt-repository ppa:deadsnakes/ppa -y
- sudo apt-get update
б. Подготовить ansible конфигурации, можно воспользоваться, например Kubespray
Скачиваем репозиторий с Kubespray
git clone https://github.com/kubernetes-sigs/kubespray
Устанавливаем зависимости
python3.10 -m pip install --upgrade pip
pip3 install -r requirements.txt
Копируем шаблон с inventory
файлом
cp -rfp inventory/sample inventory/mycluster
Корректируем файл inventory.ini
, где прописываем актуальные ip адреса виртуальных машин, развернутых в предвдущих пунктах, в качестве CRI будем использовать containerd
, а запуск etcd
будет осущуствляться на мастере.
# ## Configure 'ip' variable to bind kubernetes services on a
# ## different ip than the default iface
# ## We should set etcd_member_name for etcd cluster. The node that is not a etcd member do not need to set the value, or can set the empty string value.
[all]
node1 ansible_host=51.250.71.251 ansible_user=leo ansible_ssh_private_key_file=~/.ssh/id_rsa # ip=192.168.10.7 etcd_member_name=etcd1
node2 ansible_host=84.201.174.252 ansible_user=leo ansible_ssh_private_key_file=~/.ssh/id_rsa # ip=192.168.10.10 etcd_member_name=etcd2
node3 ansible_host=89.169.166.190 ansible_user=leo ansible_ssh_private_key_file=~/.ssh/id_rsa # ip=192.168.10.19 etcd_member_name=etcd3
# node4 ansible_host=95.54.0.15 # ip=10.3.0.4 etcd_member_name=etcd4
# node5 ansible_host=95.54.0.16 # ip=10.3.0.5 etcd_member_name=etcd5
# node6 ansible_host=95.54.0.17 # ip=10.3.0.6 etcd_member_name=etcd6
# ## configure a bastion host if your nodes are not directly reachable
# [bastion]
# bastion ansible_host=x.x.x.x ansible_user=some_user
[kube_control_plane]
node1
# node2
# node3
[etcd]
node1
# node2
# node3
[kube_node]
node2
node3
# node4
# node5
# node6
[calico_rr]
[k8s_cluster:children]
kube_control_plane
kube_node
calico_rr
в. Задеплоить Kubernetes на подготовленные ранее инстансы, в случае нехватки каких-либо ресурсов вы всегда можете создать их при помощи Terraform.
ansible-playbook -i inventory/mycluster/inventory.ini cluster.yml -b -v
- Альтернативный вариант: воспользуйтесь сервисом Yandex Managed Service for Kubernetes
а. С помощью terraform resource для kubernetes создать региональный мастер kubernetes с размещением нод в разных 3 подсетях
б. С помощью terraform resource для kubernetes node group
Альтернативный вариант рассмотрен в одном из домашних заданий, где бул подготовлен соответствующий манифест, но для выполнения дипломного проекта готовый кластер Yandex Managed Service for Kubernetes
дороже подготовленного самостоятельно в варианте 1.
Ожидаемый результат:
- Работоспособный Kubernetes кластер. Подключаемся к
control-plane
ноде
ssh leo@51.250.71.251
Проверяем, что кластер состоит из одной control-plane
ноды и двух worker
нод
kubectl get nodes
3. В файле
~/.kube/config
находятся данные для доступа к кластеру.
cat ~/.kube/config
- Команда
kubectl get pods --all-namespaces
отрабатывает без ошибок.
В качестве промежуточного итога прилагаю terraform манифест и файлы, необходимые для создания инфраструктуры, описанной выше:
Создание тестового приложения
Для перехода к следующему этапу необходимо подготовить тестовое приложение, эмулирующее основное приложение разрабатываемое вашей компанией.
Способ подготовки:
- Рекомендуемый вариант:
а. Создайте отдельный git репозиторий с простым nginx конфигом, который будет отдавать статические данные.
В соответствии с рекомендуемым вариантом создан репозиторий nginx-static
Далее копируем репозиторий на виртуальную машину в одноименную директорию
git init
git clone https://github.com/LeonidKhoroshev/nginx-static.git
Создаем внутри проекта директорию static
и в ней указываем конфигурацию файла основной стартовой страницы index.html и styles.css, созданного для улучшения внешнего вида нашей веб-страницы. Также создаем директорию images для хранения там фоновой картинки.
б. Подготовьте Dockerfile для создания образа приложения.
Переходим в корневую директорию и создаем Dockerfile
следующей конфигурации
FROM nginx:latest
COPY ./static /usr/share/nginx/html
EXPOSE 80
Сохраняем изменения в ветке main
нашего репозитория:
git add .
git commit -m "first commit"
git push https://github.com/LeonidKhoroshev/nginx-static main
Далее авторизовываемся на DockerHub и в консоли и собираем docker
образ
docker login
docker build -t leonid1984/nginx-static:latest .
И размещаем его в нашем хранилище на DockerHub
docker push leonid1984/nginx-static:latest
- Альтернативный вариант:
а. Используйте любой другой код, главное, чтобы был самостоятельно создан Dockerfile.
Ожидаемый результат:
- Git репозиторий с тестовым приложением и Dockerfile.
- Регистри с собранным docker image. В качестве регистри может быть DockerHub или Yandex Container Registry, созданный также с помощью terraform.
Подготовка cистемы мониторинга и деплой приложения
Уже должны быть готовы конфигурации для автоматического создания облачной инфраструктуры и поднятия Kubernetes кластера.
Теперь необходимо подготовить конфигурационные файлы для настройки нашего Kubernetes кластера.
Цель: 1. Задеплоить в кластер prometheus, grafana, alertmanager, экспортер основных метрик Kubernetes.
Выполним установку вышеуказанных мониторингов через helm
. Сначала установим helm
на control-plane
ноду
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
Создаем отдельное простанство имен для мониторинга
kubectl create namespace monitoring
Добавляем репозиторий helm
c prometheus
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
Устанавливаем kube-prometheus-stack
(установка Prometheus
, Grafana
, Alertmanager
, node-exporter
и kube-state-metrics
)
helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring
Проверяем, что все поры работают нормально
kubectl get pods -n monitoring
Получаем пароль от Grafana
kubectl get secret -n monitoring prometheus-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
Настраиваем доступ к Grafana
по внешнему ip адресу, для чего создаем файл values.yml
grafana:
service:
type: NodePort
nodePort: 32000
Обновляем helm
чарт
helm upgrade prometheus prometheus-community/kube-prometheus-stack -n monitoring -f values.yml
Далее настраиваем необходимые метрики, так для k8s кластера. Для простоты воспользуемся готовым дашбордом из того, что предлагает Grafana
- ID 315
Проверем наличие новых дашбордов
Видим, что из кластера поступают данные, но в пока мы не деплоили наше приложение, мониторинг не слишком информативен ввиду отсутствия рабочей нагрузки
- Задеплоить тестовое приложение, например, nginx сервер отдающий статическую страницу.
Cоздаем деплой nginx-deployment.yml
, куда прописываем следующую конфигурацию
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-static
labels:
app: nginx-static
spec:
replicas: 3
selector:
matchLabels:
app: nginx-static
template:
metadata:
labels:
app: nginx-static
spec:
containers:
- name: nginx
image: leonid1984/nginx-static:latest
ports:
- containerPort: 80
Также нам необходим сервис nginx-service.yml
piVersion: v1
kind: Service
metadata:
name: nginx-static
labels:
app: nginx-static
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 32001
selector:
app: nginx-static
Применяем изменения и проверяем результат
kubectl apply -f nginx-deployment.yml
kubectl apply -f nginx-service.yml
kubectl get pods -l app=nginx-static
Способ выполнения: 1. Воспользоваться пакетом kube-prometheus, который уже включает в себя Kubernetes оператор для grafana, prometheus, alertmanager и node_exporter. Альтернативный вариант - использовать набор helm чартов от bitnami.
- Если на первом этапе вы не воспользовались Terraform Cloud, то задеплойте и настройте в кластере atlantis для отслеживания изменений инфраструктуры. Альтернативный вариант 3 задания: вместо Terraform Cloud или atlantis настройте на автоматический запуск и применение конфигурации terraform из вашего git-репозитория в выбранной вами CI-CD системе при любом комите в main ветку. Предоставьте скриншоты работы пайплайна из CI/CD системы.
Ожидаемый результат: 1. Git репозиторий с конфигурационными файлами для настройки Kubernetes (в качестве конфигурационных файлов представлены деплой nginx-deployment.yml и сервис nginx-service.yml для развертывания нашей тестовой страницы). 2. Http доступ к web интерфейсу grafana. 3. Дашборды в grafana отображающие состояние Kubernetes кластера. 4. Http доступ к тестовому приложению.
Установка и настройка CI/CD
Осталось настроить ci/cd систему для автоматической сборки docker image и деплоя приложения при изменении кода.
Цель:
- Автоматическая сборка docker образа при коммите в репозиторий с тестовым приложением.
- Автоматический деплой нового docker образа.
Можно использовать teamcity, jenkins, GitLab CI или GitHub Actions.
Для настройки CI/CD процессов нашего проекта выбран Jenkins
как наиболее широко применяемое open-source решение. Ранее в соответствующем модуле обучения установка Jenkins
была описана посредством создания двух виртуальных машин jenkins-master
и jenkins-agent
на базе следующего кода terraform. В целях экономии вычислительных ресурсов, а также общей архитектуры и логики работы нашей инфраструктуры в данном задании выбран вариант запуска Jenkins
в k8s по следующей инструкции.
Копируем репозиторий
git clone https://github.com/scriptcamp/kubernetes-jenkins
Создаем новое пространство имен, чтобы было проще отслеживать работу подов и сервисов
kubectl create namespace devops-tools
Создаем сервисный аккаунт для Jenkins
, оставляя без изменений файл serviceAccount.yaml
из скачанного репозитория
kubectl apply -f serviceAccount.yaml
Указываем в deployment.yaml
тома постоянного хранения данных (настройки пользователя, пайплайны и т.д., так как наш кластер использует ради экономии прерываемые виртуальные машины).
volumeMounts:
- name: jenkins-data
mountPath: /var/jenkins_home
- name: docker-socket
mountPath: /var/run/docker.sock
- name: docker-bin
mountPath: /tmp/docker-bin
volumes:
- name: jenkins-data
persistentVolumeClaim:
claimName: jenkins-pvc
- name: docker-socket
hostPath:
path: /var/run/docker.sock
- name: docker-bin
emptyDir: {}
И соответственно создаем требуемый persistent volume
apiVersion: v1
kind: PersistentVolume
metadata:
name: jenkins-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: "/var/jenkins_home"
А также persistent volume claim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-pvc
namespace: devops-tools
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Для корректной работы необходимо создать директорию /var/jenkins_home
на всех нодах нашего кластера, для чего необходимо в deployment.yaml
добавить инитконтейнер, устанавливающий docker
и git
initContainers:
- name: install-docker-git
image: ubuntu:22.04
command:
- sh
- -c
- |
apt-get update && \
apt-get install -y curl gnupg && \
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null && \
apt-get update && \
apt-get install -y docker-ce-cli && \
mkdir -p /tmp/docker-bin && \
cp /usr/bin/docker /tmp/docker-bin/docker
apt-get install -y git
volumeMounts:
- name: docker-bin
mountPath: /tmp/docker-bin
- name: jenkins-data
mountPath: /var/jenkins_home
- name: docker-socket
mountPath: /var/run/docker.sock
Применяем изменения и проверяем успешный запуск Jenkins
kubectl apply -f pv.yaml
kubectl apply -f pvc.yaml
kubectl apply -f deployment.yaml
kubectl get deployments -n devops-tools
kubectl get pods -n devops-tools
Далее создаем соответствующий сервис. Незначительно корректируем дефортный файл service.yaml
из скачанного репозитория, указав nodePort: 32002
, так как дефолтный порт 32000
уже занят мониторингом (Grafana), а на порту 32001
работает наш сервер nginx
.
Запускаем сервис
kubectl apply -f service.yaml
Для первого входа через веб-интерфейс определяем пароль
kubectl logs jenkins-cf789dc4d-l2v56 --namespace=devops-tools
Входим в графический интерфейс и устанавливаем плагины, предлагаемые Jenkins
. Далее осуществляем стандартную настройку Jenkins
, указывая логин, пароль и электронную почту в соответствующих пунктах меню. Далее копирую ссылку url для быстрого доступа (для упрощения задания ip адреса виртуальных машин, участвующих в проекте сделаны статическими).
http://89.169.145.151:32002/
Далее необходимо настроить pipeline. Сборка и отправка в регистр docker-image
по условиям задания должна осуществляться при любом коммите в репозитории.
Для этого переходим в репозиторий и создаем webhook
в веб-интерфейсе GitHub
Также необходимо настроить Docker Credentials
в веб-интерфейсе Jenkins
.
Далее настраиваем агенты для сборки на основе Kubernetes pod
. Для этого сначала установим плагин Kubernetes
для Jenkins
, далее создаем новое облако Kubernetes
, в настройках прописываем пространство имен devops-tools
, в котором развернут под с Jenkins
и также через графический интерфейс тестируем соединение с кластером.
Убедившись в наличии подключения, добавляем шаблон пода, который будет являться нашим сборочным агентом. Задаем название jenkins-agent
, указываем пространство имен и image
inbound-agent
Подробная инструкция по созданию и настройке агента доступна по ссылке. Поскольку после публикации статьи в Jenkins прошел ряд обновлений, то не вся информация в ней актуальна (например названия плагинов), но в целом описанный метод является рабочим (на период сентября 2024 года).
Также для автоматизации нашего проекта необходима организация доступа через токен к DockerHub
, Получаем токен в личном кабинете на https://app.docker.com
Сохраняем токен в credentials
После того как предварительная настройка Jenkins
произведена, создадим pipeline
для нашего проекта
pipeline {
agent any
environment {
DOCKER_HUB_REPO = 'leonid1984/nginx-static'
DOCKER_CREDENTIALS_ID = 'docker-hub-credentials' // ID учетных данных Docker Hub в Jenkins
KUBECONFIG_CREDENTIALS_ID = 'kubeconfig-credentials' // ID учетных данных для подключения к Kubernetes в Jenkins
}
stages {
stage('Checkout') {
steps {
// Получение кода из GitHub
git branch: 'main', url: 'https://github.com/LeonidKhoroshev/nginx-static.git'
}
}
stage('Build Docker Image') {
steps {
script {
// Получение текущего тега, если есть
def tag = env.GIT_TAG_NAME ?: 'latest'
// Сборка Docker-образа
sh "docker build -t ${DOCKER_HUB_REPO}:${tag} ."
}
}
}
stage('Push to Docker Hub') {
steps {
withCredentials([string(credentialsId: 'docker_hub_pat', variable: 'DOCKER_HUB_PAT')]) {
sh """
echo $DOCKER_HUB_PAT | docker login -u leonid1984 --password-stdin
docker push leonid1984/nginx-static:latest
"""
}
}
}
stage('Deploy to Kubernetes') {
when {
tag "v*" // Деплой выполняется только при создании тега
}
steps {
script {
withCredentials([file(credentialsId: KUBECONFIG_CREDENTIALS_ID, variable: 'KUBECONFIG')]) {
def tag = env.GIT_TAG_NAME ?: 'latest'
// Применение конфигурации деплоя в Kubernetes
sh """
kubectl set image deployment/nginx-static-deployment nginx-static=${DOCKER_HUB_REPO}:${tag}
kubectl rollout status deployment/nginx-static-deployment
"""
}
}
}
}
}
post {
success {
echo 'Pipeline completed successfully!'
}
failure {
echo 'Pipeline failed!'
}
}
}
Проверяем работу pipeline
Сборка прошла успешно
Ожидаемый результат:
- Интерфейс ci/cd сервиса доступен по http.
- При любом коммите в репозитории с тестовым приложением происходит сборка и отправка в регистр Docker образа.
- При создании тега (например, v1.0.0) происходит сборка и отправка с соответствующим label в регистри, а также деплой соответствующего Docker образа в кластер Kubernetes.
Что необходимо для сдачи задания?
- Репозиторий с конфигурационными файлами Terraform и готовность продемонстрировать создание всех ресурсов с нуля.
- Пример pull request с комментариями созданными atlantis’ом или снимки экрана из Terraform Cloud или вашего CI-CD-terraform pipeline.
- Репозиторий с конфигурацией ansible, если был выбран способ создания Kubernetes кластера при помощи ansible.
- Репозиторий с Dockerfile тестового приложения и ссылка на собранный docker image.
- Репозиторий с конфигурацией Kubernetes кластера (в моем случае конфигурация кластера задана в репозитории с kubespray в файле inventory.ini ).
- Ссылка на тестовое приложение и веб интерфейс Grafana с данными доступа: логин -
admin
пароль -prom-operator
. - Все репозитории рекомендуется хранить на одном ресурсе (github, gitlab).
Дополнительно прилагаю файлы для развертывания Jenkins
в k8s