Infrastructure Kubernetes in Yandex Cloud: from design to CI/CD
We often see teams spending weeks manually configuring Kubernetes in Yandex Cloud and facing problems: incorrect network topology, resource leaks, lack of observability. Yandex Managed Kubernetes removes some headaches, but without proper architecture, the cluster can become a source of failures. Our experience (5+ years, 50+ clusters) shows: the key to stable operation is following best practices from the start. If you need a production-grade cluster, contact us for an audit.
Advantages of Yandex Managed Kubernetes
Yandex Managed Kubernetes is the most mature managed Kubernetes among Russian cloud providers. Deep integration with the YC ecosystem: Container Registry, Managed Databases, Object Storage, Application Load Balancer — everything is managed natively via Kubernetes resources. For projects on Yandex Cloud, this removes significant operational overhead compared to a self-deployed cluster. You get automatic control plane updates, integration with service accounts, and ready-made monitoring solutions.
How We Design Cluster Architecture
The first question is zonal vs. regional master. Zonal (one control plane in one zone) is cheaper by 30%. Regional (three master nodes in three zones) is HA. For production, we use only regional: losing one zone does not bring down the cluster.
The second question is the Kubernetes version. YC supports the current minor and two previous ones (typically 1.27–1.29). Release channel: STABLE for production, REGULAR if you need fresher versions, RAPID for experiments.
The third is network topology. The cluster should live in a private subnet, without a public IP on the master. Access to kubectl — only via VPN or bastion. This reduces the attack surface.
Terraform: Full Cluster Configuration
# Service accounts
resource "yandex_iam_service_account" "k8s_master" {
name = "k8s-master-sa"
folder_id = var.folder_id
}
resource "yandex_iam_service_account" "k8s_nodes" {
name = "k8s-nodes-sa"
folder_id = var.folder_id
}
# Roles for master SA
resource "yandex_resourcemanager_folder_iam_member" "k8s_master_roles" {
for_each = toset(["k8s.clusters.agent", "vpc.publicAdmin", "load-balancer.admin"])
folder_id = var.folder_id
role = each.value
member = "serviceAccount:${yandex_iam_service_account.k8s_master.id}"
}
# Roles for node SA
resource "yandex_resourcemanager_folder_iam_member" "k8s_nodes_roles" {
for_each = toset(["container-registry.images.puller", "monitoring.editor"])
folder_id = var.folder_id
role = each.value
member = "serviceAccount:${yandex_iam_service_account.k8s_nodes.id}"
}
# Cluster
resource "yandex_kubernetes_cluster" "main" {
name = "production-cluster"
folder_id = var.folder_id
network_id = yandex_vpc_network.main.id
master {
regional {
region = "ru-central1"
dynamic "location" {
for_each = {
a = yandex_vpc_subnet.private_a.id
b = yandex_vpc_subnet.private_b.id
d = yandex_vpc_subnet.private_d.id
}
content {
zone = "ru-central1-${location.key}"
subnet_id = location.value
}
}
}
version = "1.28"
public_ip = false
security_group_ids = [yandex_vpc_security_group.k8s_master.id]
maintenance_policy {
auto_upgrade = true
maintenance_window {
day = "sunday"
start_time = "03:00"
duration = "3h"
}
}
}
service_account_id = yandex_iam_service_account.k8s_master.id
node_service_account_id = yandex_iam_service_account.k8s_nodes.id
release_channel = "STABLE"
network_policy_provider = "CALICO"
}
Node Groups: Workers and Specialized Nodes
For production, we recommend separating nodes by purpose using taints/labels:
# General worker nodes
resource "yandex_kubernetes_node_group" "workers" {
cluster_id = yandex_kubernetes_cluster.main.id
name = "workers"
version = "1.28"
instance_template {
platform_id = "standard-v3"
resources {
cores = 4
memory = 8
}
boot_disk {
type = "network-ssd"
size = 64
}
network_interface {
subnet_ids = [
yandex_vpc_subnet.private_a.id,
yandex_vpc_subnet.private_b.id,
yandex_vpc_subnet.private_d.id,
]
nat = false
security_group_ids = [yandex_vpc_security_group.k8s_nodes.id]
}
metadata = {
ssh-keys = "ubuntu:${file("~/.ssh/id_rsa.pub")}"
}
}
scale_policy {
auto_scale {
initial = 3
min = 3
max = 10
}
}
allocation_policy {
location {
zone = "ru-central1-a"
}
location {
zone = "ru-central1-b"
}
location {
zone = "ru-central1-d"
}
}
node_taints = []
node_labels = {
"node-type" = "worker"
}
}
# Nodes for stateful workloads (DB-sidecar, cache)
resource "yandex_kubernetes_node_group" "stateful" {
cluster_id = yandex_kubernetes_cluster.main.id
name = "stateful"
version = "1.28"
instance_template {
platform_id = "standard-v3"
resources {
cores = 8
memory = 32
}
boot_disk {
type = "network-ssd"
size = 100
}
network_interface {
subnet_ids = [yandex_vpc_subnet.private_a.id]
nat = false
security_group_ids = [yandex_vpc_security_group.k8s_nodes.id]
}
}
scale_policy {
fixed_scale {
size = 2
}
}
allocation_policy {
location {
zone = "ru-central1-a"
}
}
node_taints = ["dedicated=stateful:NoSchedule"]
node_labels = {
"node-type" = "stateful"
}
}
Basic Components and Integrations
ALB Ingress Controller
YC Application Load Balancer integrates with Kubernetes via ALB Ingress Controller. This is a native L7 load balancer of Yandex Cloud, managed through Kubernetes Ingress resources. Installation:
helm upgrade --install yc-alb-ingress-controller \
oci://cr.yandex/yc-marketplace/yandex-cloud/yc-alb-ingress-controller/chart \
--version 0.1.x \
--namespace yc-alb-ingress-controller-system \
--create-namespace \
--set-string folder_id=<folder-id> \
--set-string cluster_id=<cluster-id>ALB is automatically created in Yandex Cloud, TLS termination at the load balancer level. Alternative — ingress-nginx with Network Load Balancer (more familiar stack, less YC-specific).
Secrets via Yandex Lockbox
YC Lockbox is a managed secrets service. Integration with Kubernetes via External Secrets Operator:
helm upgrade --install external-secrets external-secrets \
--repo https://charts.external-secrets.io \
--namespace external-secrets \
--create-namespaceAn example of ExternalSecret for syncing a DB password can be found in the External Secrets Operator documentation.
Cluster Monitoring
YC automatically collects system metrics of nodes and the cluster. For full application monitoring, we install kube-prometheus-stack:
helm upgrade --install kube-prometheus-stack \
prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--set prometheus.prometheusSpec.retention=30d \
--set grafana.adminPassword=$(openssl rand -base64 24) \
--set alertmanager.config.global.slack_api_url=<webhook-url>Metrics from Prometheus can be exported to Yandex Monitoring via yc-unified-agent — then alerts and dashboards live in the same place as the rest of the YC infrastructure.
NetworkPolicy with Calico
Enable at the cluster level (network_policy_provider = "CALICO"). The basic principle: default deny for the entire namespace, explicitly allow only necessary communications. After the deny, add allow policies by label.
How to Set Up CI/CD?
For continuous delivery to the cluster, we use a GitOps approach with ArgoCD or familiar CI/CD pipelines GitLab CI / GitHub Actions. Configure kubectl via a service account with the cluster-admin role, and the pipeline can deploy manifests. We integrate everything within the project, including automatic image updates via Flux or ArgoCD Image Updater.
What We Deliver
- Cluster architecture design considering load and budget constraints.
- Full configuration via Terraform (cluster, node groups, security groups).
- Installation and configuration of basic components: ALB Ingress Controller, External Secrets, kube-prometheus-stack.
- Implementation of Network Policy for service isolation.
- CI/CD integration (GitLab CI / GitHub Actions / ArgoCD) and documentation.
- Team training: how to manage the cluster, deploy, monitor.
- 1-month warranty support after launch.
Work Stages
- Design — network topology, number and types of node groups, Ingress selection, cost estimation.
- Terraform — cluster, node groups, SA, security groups.
- Basic components — Ingress Controller, External Secrets, monitoring.
- Network Policy — namespace isolation, default deny.
- CI/CD integration — setting up deployment to the cluster.
- Documentation and training — Runbook, architecture, instructions.
Timelines and Cost
| Task | Duration |
|---|---|
| Cluster + basic components | 3-5 days |
| Full infrastructure with monitoring and CI/CD | 1-2 weeks |
| Migration of existing workloads to the cluster | 2-4 weeks |
| Component | Purpose | Tool |
|---|---|---|
| Ingress | L7 balancing | ALB / ingress-nginx |
| Secrets | Secret management | External Secrets + Lockbox |
| Monitoring | Metrics, alerts, logs | kube-prometheus-stack, Yandex Monitoring |
Cost is calculated individually after an audit of your infrastructure. We always offer the best price/quality ratio — average savings compared to DIY is 25–40% due to automation and best practices. Using spot instances allows savings up to 60% on compute resources.
Want a stable and secure cluster? Contact us — we will evaluate your project and offer timelines.







