Використання перших скриптів для деплою DevOps для додатку в K8S
Після створення облікового запису служби для доступу до нашого прикладу простору імен у статті тут, ми можемо почати використовувати його для деплою першого сервісу.
Створимо простий додаток для деплою, який буде базуватися на контейнері Docker.
Створіть папку зі структурою:
- Dockerfile
- Makefile
- html/index.html
Dockerfile створить контейнер для додатку на основі nginx-проксі, який буде віддавати html файл.
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY ./html/ /usr/share/nginx/html/
EXPOSE 80
Файл index.hml виглядає так:
Example is here
І нарешті, нам потрібен Makefile, де потрібно змінити реєстр та інші параметри.
# Variables
REGISTRY = registry.example.com
PROJECT = example
IMAGE_NAME = example-web-ui
TAG = latest
FULL_IMAGE_NAME = $(REGISTRY)/$(PROJECT)/$(IMAGE_NAME):$(TAG)
CONTAINER_NAME = example-web-ui-app
PORT = 8080
# Build the Docker image
build:
docker build -t $(FULL_IMAGE_NAME) .
# Run the Docker container
run:
docker run --rm --name $(CONTAINER_NAME) -p $(PORT):80 $(FULL_IMAGE_NAME)
# Push the image to the registry
push:
docker push $(FULL_IMAGE_NAME)
Давайте побудуємо та заштовхаємо наш образ
make
make push
Після того як ми заштовхали образ, ми готові до деплою додатку, але для самого деплою давайте використаємо Terraform.
Створимо додаткову папку ‘infra’ у нашому репозиторії та помістимо там terraform-скрипти, які визначатимуть деплой, сервіс та http-маршрут до сервісу.
Main.tf
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0" # Replace with the latest compatible version
}
}
}
provider "kubernetes" {
# Use kubeconfig from local environment or specify directly
config_path = "~/.kube/config" # This path should be modified if necessary
}
provider "docker" {
registry_auth {
address = "registry.example.com"
username = "example"
password = var.registry_example_password
}
}
resource "kubernetes_secret" "docker_registry" {
metadata {
name = "docker-registry-secret"
namespace = var.namespace
}
data = {
".dockerconfigjson" = jsonencode({
auths = {
"https://registry.example.com" = {
username = "example"
password = var.registry_example_password
email = "[email protected]"
}
}
})
}
type = "kubernetes.io/dockerconfigjson"
}
Основний файл визначає плагіни/постачальників, яких ми будемо використовувати, і секрет реєстру Docker для приватного реєстру з образом.
Давайте створимо підпапку .kube та помістимо туди конфігураційний файл, який ми створили раніше тут. Додатково давайте додамо файл ‘.kube/secrets.tfvars’, щоб зберігати пароль для приватного реєстру контейнерів.
registry_depecher_password = "..."
Також нам потрібно визначити секрети як змінні, щоб ми могли використовувати їх у Terraform.
Створимо файл ‘secrets.tf’
variable "registry_depecher_password" {
description = "The password for the registry"
sensitive = true
}
Наступний крок — визначити змінні, які ми будемо використовувати у файлі variables.tf
variable "namespace" {
description = "Kubernetes namespace"
type = string
}
variable "cos" {
description = "Class of Service"
type = string
}
variable "project" {
description = "Project name"
type = string
}
variable "hostnames" {
description = "List of hostnames for the HTTP route"
type = list(string)
}
І налаштуємо самі змінні, які можуть бути специфічними для кожного середовища.
Створимо файл ‘terraform.tfvars’.
Ім’я має бути таким, щоб Terraform міг автоматично його завантажити.
cos = "prod"
project = "example-dot-com"
namespace = "prod-example-dot-com"
hostnames = [
"www.example.com"
]
Наступний крок — створити сервіс у файлі ‘service.tf’.
resource "null_resource" "image_change_trigger" {
triggers = {
image_version = timestamp() # Це може бути на основі динамічного значення або мітки часу
}
provisioner "local-exec" {
command = "kubectl rollout restart deployment example-web-ui -n ${var.namespace}"
}
}
resource "kubernetes_deployment" "web_ui_deployment" {
metadata {
name = "example-web-ui"
namespace = var.namespace
labels = {
app = "example-web-ui"
cos = var.cos
project = var.project
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "example-web-ui"
}
}
template {
metadata {
labels = {
app = "example-web-ui"
}
}
spec {
container {
name = "example-web-ui"
image = "registry.example.com/example/example-web-ui:latest"
image_pull_policy = "Always"
port {
container_port = 80
}
}
image_pull_secrets {
name = kubernetes_secret.docker_registry.metadata[0].name
}
}
}
}
depends_on = [null_resource.image_change_trigger]
}
resource "kubernetes_service" "web_ui_service" {
metadata {
name = "example-web-ui"
namespace = var.namespace
}
spec {
selector = {
app = "example-web-ui"
}
port {
port = 80
target_port = 80
}
type = "ClusterIP"
}
}
Тут ми маємо додатковий null-сервіс, який буде запускати перезавантаження додатку кожного разу, коли ми застосовуємо конфігурацію Terraform. Це потрібно для того, щоб оновити сервіс і знову завантажити образ з параметром ‘imagepullpolicy = “Always”’ щоразу, оскільки ми використовуємо тег “latest”. Іншим чином Kubernetes не знатиме, що тег було змінено.
І остання конфігурація, яку нам потрібно зробити, — це ‘route.tf’.
resource "kubernetes_manifest" "http_route" {
manifest = {
apiVersion = "gateway.networking.k8s.io/v1"
kind = "HTTPRoute"
metadata = {
name = "example-http-route"
namespace = var.namespace
}
spec = {
parentRefs = [
{
group = "gateway.networking.k8s.io"
kind = "Gateway"
name = "external-https"
namespace = "gateway-infra"
}
]
hostnames = var.hostnames
rules = [
{
matches = [
{
path = {
type = "PathPrefix"
value = "/"
}
}
]
backendRefs = [
{
name = "example-web-ui"
port = 80
}
]
}
]
}
}
}
Це може бути GrpcRoute або будь-який інший тип. Мета цього маршруту — підключитися до існуючого спільного сервісу-шлюзу, який займається сертифікатами TLS та іншою інфраструктурою. На цьому рівні додатку нам потрібно тільки знати доменне ім’я та маршрути, які ми будемо обслуговувати.
Додатково ми можемо додати кілька скриптів для автоматизації.
plan.sh
terraform plan -var-file=".kube/secrets.tfvars"
та apply.sh
terraform apply -var-file=".kube/secrets.tfvars"
Тепер ми готові виконати команди Terraform.
terraform init
./plan.sh
./apply.sh
Після цього ми отримаємо щось таке:
Apply complete! Resources: 1 added, 1 changed, 1 destroyed.
Отже, насолоджуйтесь!
Перекладено з: Deploy a simple service with Nginx on Kubernetes using Terraform