DevOps Is Bullshit: Ảo tưởng 'You build it, you run it' và sự trỗi dậy của Platform Engineering

DevOps Is Bullshit: Ảo tưởng 'You build it, you run it' và sự trỗi dậy của Platform Engineering

Mục lục

Một kỹ sư backend cần IAM role để service của mình đọc được bucket S3 chứa hoá đơn. Anh ta mở Jira, chọn template “Infrastructure Request”, điền 12 trường, gắn label đúng như README hướng dẫn, rồi bấm Create. Ba ngày sau role mới xuất hiện.

Ba ngày đó anh ta không ngồi không. Anh ta viết code với một biến môi trường trỏ vào role cũ, chạy được ở staging vì staging dùng credential của chính anh ta, rồi đẩy lên production với một quyền mà sau này không ai giải thích được nó đến từ đâu.

Cái team xử lý ticket kia có tên là “DevOps”.

Công ty bên cạnh thì ngược lại. Không có ticket, không có hàng đợi, không có ai để hỏi. Kỹ sư backend tự viết Terraform, tự dựng RDS, tự cấu hình security group, tự map DNS. Nghe rất “you build it, you run it”. Cho đến 2 giờ sáng, khi CloudWatch báo connection pool cạn vì một index thiếu trong Postgres, và người bị gọi dậy là anh chàng vừa viết 400 dòng code nghiệp vụ cách đây hai tuần.

Cả hai công ty đều tự gọi mình là DevOps. Cả hai đều đang làm sai. Và cái sai này không đến từ sự lười biếng, nó đến từ chỗ một ý tưởng văn hóa đã bị nén thành một chức danh, rồi chức danh đó bị nén thành một hàng đợi.

1. DevOps ban đầu không phải là một chức danh

Năm 2009, Patrick Debois tổ chức DevOpsDays ở Ghent. Ý tưởng cốt lõi không phải là công cụ. Nó là việc xoá bỏ bức tường giữa người viết code và người vận hành hệ thống, để hai nhóm cùng chịu trách nhiệm về một thứ duy nhất: sản phẩm chạy được cho người dùng.

Cùng lúc đó, Werner Vogels của Amazon có một câu đã thành khẩu hiệu: “You build it, you run it”. Trong bối cảnh Amazon năm 2006, đó là một câu giải phóng. Nó nói với các team rằng họ không được ném code qua tường cho ai khác, rằng chất lượng vận hành là một phần của định nghĩa “hoàn thành”.

Vấn đề là Amazon nói câu đó với một hậu thuẫn rất cụ thể: hạ tầng AWS, công cụ nội bộ dùng chung, và một tổ chức mà mọi team đều có kỹ sư đủ năng lực hạ tầng. Các công ty khác chỉ lấy được câu khẩu hiệu, không lấy được hậu thuẫn. Và thế là ra đời hai kiểu đau khổ khác nhau dưới cùng một cái mác.

2. Bẫy thứ nhất: “DevOps team” thực chất là sysadmin mặc áo mới

Kiểu thất bại đầu tiên là thành lập một team DevOps. Nghe có vẻ hợp lý: gom hết người biết về hạ tầng vào một chỗ, cho họ một cái tên hiện đại. Nhưng hãy nhìn vào việc team đó thật sự làm mỗi ngày.

Họ dùng Terraform và YAML để làm những việc thủ công cho team engineering. Cần một database? Tạo ticket. Cần một IAM role? Tạo ticket. Cần mở một port ra ngoài? Tạo ticket. Một team DevOps 4 người phục vụ 120 kỹ sư sẽ bị nhấn chìm trong backlog, và mỗi ticket được xử lý là một lần ai đó phải đọc yêu cầu viết bằng tiếng người, dịch nó sang HCL, mở pull request, chờ review, chạy plan, apply, rồi trả lời “xong nhé”.

Đây không phải DevOps. Đây là mô hình ticket ops cổ điển với branding mới. Bức tường giữa Dev và Ops không bị xoá, nó chỉ được sơn lại và gắn thêm một cái cửa quay.

graph TB
  subgraph "DevOps Silo (Anti-Pattern)"
    Eng["`Product Engineer
- Cần IAM role đọc S3
- Cần RDS cho feature mới
- Không biết VPC nào đang dùng`"]
    Ticket["`Jira / ServiceNow
- Template 12 trường
- Không ai đọc hết`"]
    DOps["`DevOps Team
- 4 người cho 120 engineers
- Terraform + YAML thủ công
- Backlog 200+ ticket`"]
    Infra["`Cloud Resources
- IAM, KMS, VPC, RDS, SQS
- Naming tuỳ hứng
- Guardrail không tồn tại`"]
  end

  Eng -->|"Tạo ticket"| Ticket
  Ticket -->|"Xếp hàng 3 ngày"| DOps
  DOps -->|"terraform apply"| Infra
  Infra -->|"Trả kết quả qua comment"| Eng
  DOps -.->|"Gatekeeper ở mọi phase"| Eng

  style DOps fill:#1e1e2e,stroke:#f38ba8,stroke-width:2px

Hoá đơn thật của một ticket

Thứ đắt nhất không phải là 3 ngày chờ. Thứ đắt nhất là những gì xảy ra trong lúc chờ.

Kỹ sư bị chặn không chuyển sang làm việc khác một cách hiệu quả, vì feature dở dang vẫn ngốn một phần working memory. Anh ta chọn một workaround tạm: dùng credential cá nhân, hard-code ARN, hoặc đẩy thẳng secret vào biến môi trường. Ticket được đóng, nhưng debt vừa được tạo ra và nó sẽ không bao giờ xuất hiện trong backlog của ai cả.

Kiểu thất bại này còn có một hệ quả tổ chức tinh vi hơn. Khi mọi thay đổi hạ tầng phải đi qua một team duy nhất, team đó trở thành điểm nghẽn thông tin. Không ai ngoài họ biết hạ tầng đang trông thế nào. Tri thức về cấu hình production trở thành tài sản cá nhân của vài người, vài người đó nghỉ việc thì hệ thống mất luôn bản đồ. Cory O’Daniel kể trong bài gốc rằng anh đã deploy hơn 200 Kubernetes cluster production, và copy-paste đúng một bộ Terraform module cho tất cả. Công việc nghe như một trò lừa, nhưng nó chỉ ra sự thật: phần lớn “công việc hạ tầng” ở các công ty ngoài FAANG là lặp lại thủ công, không phải thiết kế.

Code của sự lặp lại

Đây là dạng HCL mà một team DevOps phải viết đi viết lại cho mỗi service, mỗi môi trường. Nó không sai về mặt cú pháp. Nó sai về mặt kinh tế.

# infra/services/order-api/prod/main.tf - bản sao thứ 47 của cùng một file
module "order_api_queue" {
  source     = "../../../modules/sqs"
  name       = "order-api-queue-prod"
  visibility = 30
  dlq        = true
  tags       = { team = "payments", env = "prod" }
}

resource "aws_iam_role" "order_api" {
  name = "order-api-prod-exec"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "ecs-tasks.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })
}

resource "aws_iam_policy" "order_api_s3" {
  name = "order-api-prod-s3"
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect   = "Allow"
      Action   = ["s3:GetObject", "s3:PutObject", "s3:ListBucket"]
      Resource = [
        "arn:aws:s3:::invoices-prod",
        "arn:aws:s3:::invoices-prod/*",
      ]
    }]
  })
}

resource "aws_kms_key" "order_api" {
  description             = "order-api-prod encryption"
  enable_key_rotation     = true
  deletion_window_in_days = 7
}

resource "aws_cloudwatch_metric_alarm" "order_api_5xx" {
  alarm_name          = "order-api-prod-5xx"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 2
  metric_name         = "HTTPCode_Target_5XX_Count"
  namespace           = "AWS/ApplicationELB"
  period              = 60
  statistic           = "Sum"
  threshold           = 5
  treat_missing_data  = "notBreaching"
}

Bốn resource ở đây là bốn thứ mà mọi service nghiêm túc đều cần: quyền IAM tối thiểu, mã hoá at-rest, dead-letter queue, và một alarm 5xx. Không có dòng nào trong số đó là quyết định sản phẩm. Kỹ sư backend không có ý kiến gì về deletion_window_in_days hay evaluation_periods. Nhưng anh ta phải chờ 3 ngày để có chúng, và nếu anh ta tự viết thì 90% khả năng anh ta copy từ service khác, mang theo cả những giả định không còn đúng.

3. Bẫy thứ hai: “You build it, you run it” và hoá đơn cognitive load

Kiểu thất bại thứ hai không có team DevOps nào cả. Mỗi kỹ sư tự lo hạ tầng cho service của mình. Trên giấy, đây chính là “you build it, you run it” đúng nghĩa.

Trên thực tế, nó diễn ra thế này:

  • Best practice thì tự nghĩ ra trong lúc làm.
  • Bảo mật là chuyện của người rảnh, mà không ai rảnh.
  • Quy ước đặt tên thì có: nah, nah-prod, prod-nah, production-nah là bốn cái tên cho cùng một hệ thống.
  • Cost management thì tắt, vì còn credit để đốt.
  • Terraform drift thì không ai để ý, cho đến khi một apply xoá mất cái bucket mà không ai nhớ là mình đã tạo.

Điểm mấu chốt: phần lớn kỹ sư không muốn làm operations. Họ muốn xây sản phẩm. Nhưng tổ chức áp đặt lên họ, và họ làm theo một trong hai cách: học vừa đủ để mọi thứ chạy, hoặc để nhiệm vụ dồn dần vào một vài người rồi vài người đó trở thành “DevOps team” của kiểu thất bại thứ nhất. Hai cái bẫy này nối vào nhau bằng một đường thẳng.

Cognitive Load Theory áp vào hệ thống sản xuất

John Sweller đưa ra Cognitive Load Theory năm 1988, chia tải nhận thức thành ba loại:

  1. Intrinsic load: độ phức tạp nội tại của vấn đề. Xây một hệ thống thanh toán chống double-charge khó, và nó phải khó, vì bản chất bài toán khó.
  2. Extraneous load: tải đến từ cách trình bày vấn đề, không đến từ vấn đề. Việc phải nhớ rằng SNS topic của team nằm ở region khác SQS queue là extraneous load thuần tuý. Nó không dạy bạn gì về nghiệp vụ.
  3. Germane load: tải dành cho việc xây schema tư duy, tức là học thật.

Working memory có giới hạn, và giới hạn đó không tăng theo số năm kinh nghiệm. Mỗi giờ kỹ sư backend dành để nhớ rằng KMS key cần enable_key_rotation, rằng IAM role cho ECS task khác IAM role cho EC2, rằng Helm chart của team phải có podDisruptionBudget thì không còn giờ cho germane load. Nghiệp vụ không phải thứ bị cắt. Thứ bị cắt là tư duy ở tầng thiết kế, và cái giá của nó chỉ hiện ra 6 tháng sau dưới dạng một migration không ai dám làm.

Có một cách đo khá thực dụng: đếm số hệ thống mà một kỹ sư phải đăng nhập trong một tuần bình thường. Nếu con số đó lớn hơn số capability sản phẩm họ sở hữu, thì tổ chức đang trả lương cho extraneous load.

Code khi application biết quá nhiều về infra

Đây là dấu hiệu rõ nhất rằng ranh giới đã hỏng. Service nghiệp vụ đang tự giải bài toán hạ tầng:

package main

import (
	"context"
	"fmt"
	"os"

	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/sqs"
)

// Anti-pattern: application code biết về region, queue URL và cả quy trình xin quyền.
func newQueueClient(ctx context.Context) (*sqs.Client, error) {
	region := os.Getenv("AWS_REGION")
	if region == "" {
		region = "ap-southeast-1" // default cứng, không ai nhớ vì sao có
	}

	cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(region))
	if err != nil {
		return nil, fmt.Errorf("load aws config: %w", err)
	}

	queueURL := os.Getenv("ORDER_QUEUE_URL")
	if queueURL == "" {
		// Thông báo lỗi nói lên toàn bộ vấn đề của tổ chức.
		return nil, fmt.Errorf("ORDER_QUEUE_URL chưa được set, tạo ticket xin DevOps tạo queue")
	}

	return sqs.NewFromConfig(cfg), nil
}

Dòng comment cuối là một tài liệu kiến trúc vô tình viết ra: hệ thống của bạn có một hàng đợi con người nằm giữa application và hạ tầng. Không compiler nào bắt lỗi đó, nhưng nó là lỗi đắt nhất trong file.

4. Conway’s Law: kiến trúc phản chiếu tổ chức

Năm 1967, Melvin Conway viết một câu mà đến nay chưa ai phản bác được: hệ thống mà tổ chức thiết kế sẽ có cấu trúc sao chép cấu trúc giao tiếp của chính tổ chức đó.

Hệ quả thực tế rất trực tiếp. Nếu mọi thay đổi hạ tầng đều chảy qua một hàng đợi ticket, thì hạ tầng của bạn sẽ có hình dạng của hàng đợi đó: một mớ resource được tạo theo yêu cầu rời rạc, không có quy ước chung, mỗi cái là kết quả của một ticket khác nhau. Không ai thiết kế nó cả, nó tự lớn lên.

Ở chiều ngược lại, nếu mỗi team tự lo hết, hệ thống sẽ có hình dạng của các ốc đảo: mỗi team một cách làm, không có chuẩn chung, tích hợp giữa các team trở thành dự án riêng. Bạn gọi nó là autonomy, nhưng đo bằng thời gian onboard một kỹ sư mới thì nó là entropy.

Đây cũng là lý do “Inverse Conway Maneuver” tồn tại: muốn kiến trúc có hình dạng mong muốn, phải thay đổi cấu trúc giao tiếp trước, không phải vẽ lại sơ đồ sau.

5. Team Topologies: hình học tổ chức của một platform đúng nghĩa

Matthew Skelton và Manuel Pais đưa ra một mô hình hữu ích hơn “Dev vs Ops”. Có bốn loại team:

  • Stream-aligned team: sở hữu một dòng giá trị nghiệp vụ đầu-cuối, ví dụ luồng thanh toán. Đây là team tạo ra doanh thu.
  • Platform team: cung cấp dịch vụ nội bộ dưới dạng self-service, giảm tải nhận thức cho stream-aligned team.
  • Enabling team: coaching có thời hạn, giúp team khác tự làm được, rồi rút đi.
  • Complicated-subsystem team: sở hữu những subsystem cần chuyên môn sâu mà nhồi cho mọi người là vô nghĩa, ví dụ engine tìm kiếm hay runtime ML.

Và ba chế độ tương tác: Collaboration (hai team làm chung, có thời hạn), X-as-a-Service (một team dùng dịch vụ của team kia, chi phí giao tiếp thấp), Facilitating (một team giúp team kia nâng năng lực).

Đọc lại hai cái bẫy ở trên bằng từ vựng này, vấn đề trở nên rõ ràng:

  • Kiểu “DevOps team” là một platform team bị ép chạy ở chế độ Collaboration vĩnh viễn với 40 team cùng lúc. Collaboration vốn dĩ đắt, nó chỉ hiệu quả trong ngắn hạn. Kéo dài nó ra thành mô hình vận hành thường trực nghĩa là bạn đang trả giá collaboration cho mọi thay đổi hạ tầng nhỏ nhất.
  • Kiểu “you build it, you run it” là việc xoá luôn platform team, để mỗi stream-aligned team tự làm việc của complicated-subsystem team. Không ai có đủ expert, và tri thức phân tán đến mức không còn chuẩn nào.
graph LR
  subgraph "Team Topologies trong thực tế"
    SA["`Stream-aligned Team
- Sở hữu luồng thanh toán
- Cần Postgres, queue, IAM
- Không cần biết VPC`"]
    PT["`Platform Team
- Sở hữu golden path
- X-as-a-Service
- Đo adoption, không đo số ticket`"]
    EN["`Enabling Team
- Coaching 6-8 tuần
- Rồi rút đi
- Facilitating`"]
    CS["`Complicated-subsystem Team
- Search engine / ML runtime
- Chuyên môn sâu không chia sẻ được`"]
  end

  SA -->|"X-as-a-Service"| PT
  SA <-->|"Collaboration có thời hạn"| CS
  EN -.->|"Facilitating"| SA
  EN -.->|"Facilitating"| PT

  style PT fill:#1e1e2e,stroke:#a6e3a1,stroke-width:2px

Sự thật ẩn trong mô hình này: silo tri thức không phải là bug. Nếu một nửa tổ chức copy-paste cùng một module Terraform, chuyên môn đang tồn tại, chỉ là nó chưa được đóng gói lại và phân phối. Việc cần làm không phải là bắt mọi người đều biết mọi thứ, mà là đóng gói chuyên môn đó thành một dịch vụ mà người khác dùng được mà không cần học lại.

6. Platform Engineering: đối xử với platform như một sản phẩm

Platform Engineering không phải là mua một cái dashboard đẹp. Định nghĩa ngắn nhất và khó thực hiện nhất: platform là sản phẩm, và khách hàng của nó là chính các kỹ sư trong công ty (engineering customers).

Hai hệ quả tức thì của định nghĩa đó:

  1. Nếu khách hàng không dùng, platform thất bại. Ticket queue không có “khách hàng”, nó chỉ có hàng chờ. Một platform không có adoption là một dự án đắt tiền không có người dùng.
  2. Khách hàng có quyền đòi hỏi. Nếu golden path chậm hơn cách tự làm, không ai dùng nó. Chất lượng của platform được đo bằng trải nghiệm của kỹ sư, không bằng số tài nguyên quản lý được.

Golden Path: guardrail đi kèm lối mòn

Golden path không phải là bức tường. Nó là con đường nhanh nhất và an toàn nhất, có sẵn guardrail đúng chỗ. Điều quan trọng: guardrail phải nằm trong lối mòn, không nằm ở cổng phê duyệt.

Nếu bạn làm public một form hay một file YAML đơn giản và nói “self-service”, bạn không enable self-service, bạn enable shadow IT. Guardrail phải có từ đầu: IAM tối thiểu, KMS bật rotation, alarm mặc định, logging không được tắt. Người dùng chỉ cần khai báo ý định (intent), platform lo phần chi tiết triển khai.

Đây là hình dạng của một platform contract:

apiVersion: platform.company.io/v1
kind: Service
metadata:
  name: order-api
  team: payments
spec:
  runtime:
    image: registry.internal/order-api:1.42.0
    port: 8080
    replicas: 3
  capabilities:
    - postgres:
        size: small
        backup: daily
        pitr: true
    - cache: redis
    - queue:
        topic: orders.created
        dlq: true
    - objectStore:
        bucket: order-receipts
        retention: 90d
  env:
    LOG_LEVEL: info
    FEATURE_PARTIAL_REFUND: "true"
  observability:
    slo:
      availability: 99.9
      latencyP99Ms: 300

Hai mươi dòng đó thay cho hàng trăm dòng HCL, và quan trọng hơn: nó không chứa quyết định nào mà kỹ sư backend không đủ thẩm quyền đưa ra. Không có evaluation_periods. Không có deletion_window_in_days. Những thứ đó do platform sở hữu, cùng với trách nhiệm cập nhật chúng khi best practice thay đổi.

Phần platform làm ở phía sau là một reconciler. Viết bằng Go, nó nhận contract và sinh ra hạ tầng:

package platform

import (
	"context"
	"fmt"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"sigs.k8s.io/yaml"
)

// ServiceSpec là toàn bộ bề mặt mà một team product phải biết.
type ServiceSpec struct {
	APIVersion string `yaml:"apiVersion"`
	Kind       string `yaml:"kind"`
	Metadata   struct {
		Name string `yaml:"name"`
		Team string `yaml:"team"`
	} `yaml:"metadata"`
	Spec struct {
		Runtime struct {
			Image    string `yaml:"image"`
			Port     int    `yaml:"port"`
			Replicas int    `yaml:"replicas"`
		} `yaml:"runtime"`
		Capabilities []map[string]any `yaml:"capabilities"`
		Observability struct {
			SLO struct {
				Availability  float64 `yaml:"availability"`
				LatencyP99Ms  int     `yaml:"latencyP99Ms"`
			} `yaml:"slo"`
		} `yaml:"observability"`
	} `yaml:"spec"`
}

// Reconcile dịch intent thành hạ tầng. Guardrail nằm ở đây, không ở cổng duyệt.
func (r *Reconciler) Reconcile(ctx context.Context, raw []byte) error {
	var svc ServiceSpec
	if err := yaml.Unmarshal(raw, &svc); err != nil {
		return fmt.Errorf("parse service contract: %w", err)
	}

	if svc.Spec.Runtime.Replicas < 2 && svc.Spec.Observability.SLO.Availability >= 99.9 {
		return fmt.Errorf(
			"service %s khai báo SLO %.1f%% nhưng chỉ chạy %d replica: không thể đạt được",
			svc.Metadata.Name,
			svc.Spec.Observability.SLO.Availability,
			svc.Spec.Runtime.Replicas,
		)
	}

	// Guardrail mặc định, kỹ sư không phải khai báo:
	// 1. IAM role least-privilege suy ra từ danh sách capabilities.
	// 2. KMS key riêng cho từng namespace, bật rotation.
	// 3. Alarm theo SLO đã khai báo, kèm runbook link.
	// 4. Namespace riêng + NetworkPolicy default-deny.
	objs, err := r.render(ctx, &svc)
	if err != nil {
		return err
	}

	return r.apply(ctx, objs)
}

Điểm đáng chú ý là dòng kiểm tra replica so với SLO. Đây là ví dụ của một guardrail thật: nó không phải cổng phê duyệt của con người, nó là validation chạy trong vòng lặp reconcile, trả lỗi ngay tại pull request. Kỹ sư nhận phản hồi trong 30 giây thay vì 3 ngày, và lý do là lý do kỹ thuật chứ không phải “quy trình yêu cầu như vậy”.

graph TB
  subgraph "Platform Engineering (Self-service Golden Path)"
    Eng["`Product Engineer
- Khai báo intent trong service.yaml
- Không biết VPC, không biết KMS`"]
    Contract["`service.yaml
- 20-30 dòng
- Commit cùng code nghiệp vụ`"]
    API["`Platform API
- Validate schema
- Policy as code (OPA)
- Feedback trong 30 giây`"]
    Rec["`Reconciler
- Sinh Terraform / K8s manifest
- Sinh IAM, KMS, alarm mặc định
- Sinh ephemeral env theo PR`"]
    Runtime["`Runtime
- Namespace riêng
- NetworkPolicy default-deny
- Ephemeral environment`"]
    Obs["`Observability mặc định
- Metrics, log, trace
- Alarm theo SLO + runbook`"]
  end

  Eng --> Contract
  Contract -->|"git push"| API
  API -->|"Hợp lệ"| Rec
  API -.->|"Lỗi ngay tại PR"| Eng
  Rec --> Runtime
  Rec --> Obs
  Obs -->|"Alert kèm runbook, không gọi người vô can"| Eng

  style Rec fill:#1e1e2e,stroke:#a6e3a1,stroke-width:2px

Đối chiếu hai sơ đồ: sơ đồ đầu có một hàng đợi con người nằm giữa kỹ sư và hạ tầng, và mỗi lần chờ là một lần tri thức bị mất. Sơ đồ thứ hai có một validator nằm giữa kỹ sư và hạ tầng, và mỗi lần lỗi là một lần phản hồi tức thì. Khác biệt không nằm ở công cụ, nó nằm ở chỗ ai sở hữu tri thức chuyên môn và tri thức đó được phân phối bằng cách nào.

7. Platform Engineering không miễn phí

Nếu bạn đọc đến đây và nghĩ “dựng một internal developer platform” là câu trả lời, có vài cái bẫy cần biết trước, vì rất nhiều công ty đã đốt 18 tháng vào một platform không ai dùng.

Bẫy 1: dựng lại một PaaS đóng. Nếu platform của bạn chỉ có một cách để chạy một workload, và cách đó là Kubernetes, bạn không làm platform engineering, bạn làm một PaaS tệ hơn các PaaS có sẵn. Workload thật rất đa dạng: container, serverless, VM, batch job, cron, worker GPU. Một abstraction chỉ trên Kubernetes không đủ.

Bẫy 2: abstraction mà không có guardrail. Đã nói ở trên nhưng đáng nhắc lại: một web form đẹp trên đầu AWS API không phải là self-service an toàn. Không có guardrail, sự cố bảo mật đầu tiên sẽ là sự cố kết thúc mọi nỗ lực self-service, vì CISO sẽ đóng cửa và mọi thứ quay lại ticket.

Bẫy 3: không đo adoption. Platform team phải đo số team dùng golden path, thời gian từ commit đến production, số exception được cấp phép. Nếu golden path bị bỏ qua, đó là tín hiệu sản phẩm, không phải tín hiệu kỷ luật. Bốn chỉ số DORA vẫn là thước đo tốt nhất: deployment frequency, lead time for changes, change failure rate, time to restore service.

Bẫy 4: kỳ vọng team DevOps cũ tự biến thành platform team. Đây là cái bẫy đau nhất. Team đang ngập trong ticket không có năng lực và cũng không có thời gian để thiết kế API, viết tài liệu, và làm việc với người dùng nội bộ như một product team. Platform engineering cần người có kinh nghiệm phát triển phần mềm ở cả hai phía, và nó cần thời gian. Nó là một startup bên trong doanh nghiệp của bạn.

Một chi tiết nhỏ nhưng hay bị bỏ qua: ephemeral environment. Nếu mở một pull request mà không dựng được bucket, queue, database tạm cho PR đó, thì môi trường review của bạn không phải là xấp xỉ production, và bug tích hợp sẽ nằm chờ đến khi deploy thật. Khả năng tạo môi trường tạm cho cả application và dependency hạ tầng là một trong những dấu hiệu rõ nhất phân biệt platform thật với một lớp YAML trang trí.

8. Bắt đầu từ đâu

Không có lộ trình chung, nhưng có một vài nguyên tắc đã được kiểm chứng.

Bắt đầu bằng công việc lặp lại đau nhất. Không phải thứ hào nhoáng nhất. Nếu mỗi service mới đều cần cùng một bộ IAM, KMS, alarm, và mất 3 ngày để có, hãy làm đúng cái đó trước, biến nó thành một dòng khai báo.

Chọn một service phụ để migrate trước. Không phải service thanh toán. Migrate nhanh, lấy phản hồi, sửa, rồi mở rộng. Platform dựng xong rồi mới tìm người dùng là cách chắc chắn nhất để thất bại.

Đo trước khi tối ưu. Đếm số ticket hạ tầng mỗi tuần, thời gian trung bình để một service mới lên production, số hệ thống mỗi kỹ sư phải đăng nhập. Ba con số đó đủ để biết platform có tác dụng hay không.

Giữ platform mở. Người dùng phải có đường thoát nếu golden path không phù hợp, và đường thoát đó phải rẻ. Một platform không cho phép rời bỏ là một platform sẽ bị lách.

Kết: mọi hạ tầng rồi đều trở thành một platform

Có một câu trong bài gốc mà mình nghĩ là câu quan trọng nhất: cuối cùng thì mọi hạ tầng đều trở thành một platform. Câu hỏi duy nhất là platform của bạn dễ thay đổi đến mức nào.

Không có tổ chức nào tránh được điều đó. Ticket queue cũng là một platform, chỉ là một platform có API dở và thời gian phản hồi tính bằng ngày. Copy-paste Terraform cũng là một platform, chỉ là một platform không có phiên bản, không có chủ sở hữu, và không ai dám sửa.

DevOps không chết vì nó sai. Nó chết vì bị bẻ nghĩa: một tập hợp nguyên tắc về việc xoá bức tường đã bị biến thành một chức danh, rồi chức danh đó thành một hàng đợi, rồi hàng đợi đó thành một cái cớ để không phải nghĩ về thiết kế. Platform Engineering không phải là cái tên mới cho cùng một việc. Nó là việc áp dụng product mindset vào phần hạ tầng mà chúng ta đã ngầm đồng ý là commodity, và đóng gói nó thành thứ mà kỹ sư nghiệp vụ dùng được mà không phải học lại cloud từ đầu.

Nếu bạn đang phải chờ 3 ngày cho một IAM role, thì đó không phải là vấn đề quy trình. Đó là vấn đề kiến trúc tổ chức, và nó có cách sửa.

Chia sẻ :

Bài viết liên quan

Khi nào nên dùng cache (và khi nào không)

Khi nào nên dùng cache (và khi nào không)

Có một bug production mà đến giờ mình vẫn nhớ như in: user A hủy đơn hàng, nhưng app vẫn hiển thị “đang giao” trong 10 phút tiếp theo. Support nhận 30 ticket trong 1 buổi sáng. Nguyên nhân: cache TTL 10 phút, nhưng không ai invalidate khi order status thay đổi.

Đọc thêm
Graceful shutdown: lợi ích và lý do phải có

Graceful shutdown: lợi ích và lý do phải có

Có lần team mình deploy bản mới lúc 11h đêm. kubectl rollout restart xong, 30 giây sau PagerDuty réo: 200 cái 502 trong 5 giây. Khách hàng đang đặt đồ ăn thì timeout. Mình lật đật rollout undo, xong ngồi check log - hóa ra pod cũ bị SIGTERM, HTTP server tắt ngay lập tức, 50 request đang xử lý dở bị cắt ngang hết.

Đọc thêm