DevOps trên AWS: Xây dựng dự án Microservices CI/CD Pipeline với IaC, Servicemesh, Monitoring,…

Cách xây dựng CI/CD Pipeline tự động hóa nâng cao với IaC, Microservices, Service Mesh, và Monitoring…

Đây là bài viết hướng dẫn dài nhất trước giờ tôi từng viết với lượng kiến thức rất lớn mong rằng giúp ích được cho anh em lập trình. Trong bài viết này chúng ta sẽ xây dựng dự án DevOps trên AWS một CI/CD pipeline thực sự, tự động hóa việc triển khai ứng dụng dựa trên microservices trên AWS. Để làm được điều này, chúng ta sẽ tận dụng các thực hành DevOps chính như Infrastructure as Code (IaC) – Terraform, điều phối container – Amazon EKS (Elastic Kubernetes Service), tích hợp service mesh – Istio, và giám sát & ghi log toàn diện – Prometheus, Grafana và Fluentd.

Thiết kế dự án này để bao gồm các kịch bản phức tạp, thực tế mà các kỹ sư Cloud & DevOps thường xuyên gặp phải, cung cấp cho bạn hiểu biết chuyên sâu về cách chúng ta có thể kiến trúc, triển khai và quản lý các ứng dụng cloud-native hiện đại.

Mục lục

  • 1. Tổng quan dự án: Giới thiệu về dự án và các mục tiêu của nó
  • 2. Yêu cầu tiên quyết: Danh sách các công cụ, tài khoản và kiến thức cần thiết
  • 3. Sơ đồ kiến trúc: Biểu diễn trực quan kiến trúc của dự án
  • 4. Hướng dẫn chi tiết từng bước: Hướng dẫn triển khai chi tiết
    • Infrastructure as Code với Terraform: Thiết lập hạ tầng bằng Terraform
    • Thiết lập VPC và Mạng: Cấu hình môi trường mạng
    • Các quyền và chính sách IAM: Thiết lập các quyền cần thiết
    • Tạo EKS Cluster: Triển khai cụm Kubernetes trên AWS
    • Tích hợp với RDS để lưu trữ dữ liệu bền vững: Thiết lập lưu trữ cơ sở dữ liệu
    • Triển khai Jenkins trong cấu hình High Availability: Đảm bảo độ tin cậy của Jenkins
    • Thiết lập Jenkins trên EC2 với Auto-Scaling: Cấu hình Jenkins để mở rộng quy mô
    • Cấu hình kiến trúc Jenkins Master-Slave: Tối ưu hóa hiệu suất Jenkins
    • Xây dựng và Docker hóa Microservices: Chuẩn bị các dịch vụ để triển khai
    • Triển khai Service Mesh với Istio: Nâng cao khả năng giao tiếp của microservices
    • Cài đặt Istio trên EKS: Thiết lập Istio trên Kubernetes
    • Cấu hình Quản lý Traffic, Bảo mật và Khả năng quan sát: Tối ưu hóa các tính năng của Istio
    • Thiết lập Jenkins CI/CD Pipeline: Tự động hóa quy trình triển khai
    • Tích hợp GitHub, Jenkins, Docker và EKS: Kết nối tất cả các thành phần
    • Triển khai Blue-Green Deployments: Thiết lập các chiến lược triển khai nâng cao
    • Canary Deployments tự động với Istio: Triển khai các bản phát hành dần dần
    • Giám sát, Ghi log và Cảnh báo: Đảm bảo khả năng quan sát hệ thống
    • Thiết lập Prometheus và Grafana: Triển khai các giải pháp giám sát
    • Cấu hình Fluentd cho việc tập trung Log: Thiết lập tổng hợp log
    • Thiết lập Alertmanager cho Phản ứng sự cố: Cấu hình thông báo cảnh báo
  • 5. Kiểm thử và Xác thực: Xác minh chức năng của hệ thống
  • 6. Kết luận: Tóm tắt và những suy nghĩ cuối cùng

1. Tổng quan dự án

Dự án nâng cao này sẽ hướng dẫn thiết lập một CI/CD pipeline phức tạp, tự động hóa việc triển khai một ứng dụng dựa trên microservices trên AWS sử dụng EKS, Istio (service mesh) và Jenkins (cho CI/CD). Chúng ta sẽ bao quát toàn bộ vòng đời từ việc cấp phát hạ tầng (sử dụng Terraform) đến triển khai và quản lý microservices của chúng ta trong một môi trường an toàn, có khả năng mở rộng và có thể quan sát được.

2. Yêu cầu tiên quyết

  • Tài khoản AWS (Cloud): Quyền truy cập quản trị vào tài khoản AWS.
  • AWS CLI: Đã cài đặt và cấu hình với thông tin xác thực phù hợp.
  • Terraform (IAC): Đã cài đặt trên máy cục bộ của bạn.
  • kubectl (K8S cli): Đã cài đặt để quản lý các cụm Kubernetes.
  • Jenkins: Đã cài đặt trên một EC2 instance hoặc thiết lập qua Docker.
  • Docker: Đã cài đặt và đang chạy trên máy cục bộ của bạn.
  • Git (Kiểm soát phiên bản): Đã cài đặt và cấu hình.
  • Helm: Đã cài đặt để quản lý gói Kubernetes.

3. Kiến trúc Cloud

Kiến trúc của dự án chúng ta bao gồm một VPC (đám mây riêng ảo) với các subnet publicprivate. Ngoài ra còn có một EKS cluster được triển khai trên nhiều AZ (vùng sẵn sàng), Jenkins được triển khai theo cấu hình HA (tính sẵn sàng cao) trên EC2 với Auto-Scaling, cơ sở dữ liệu RDS để lưu trữ dữ liệu bền vững, và Istio để tích hợp service mesh. Việc monitoring được xử lý bởi PrometheusGrafana, trong khi Fluentd đảm nhiệm việc ghi log tập trung.

VPC
├── Public Subnet
│   └── Jenkins (EC2 with Auto-Scaling)
├── Private Subnet
│   ├── EKS Cluster (Multi-AZ)
│   │   ├── Istio (Service Mesh)
│   │   ├── Prometheus (Monitoring)
│   │   └── Grafana (Monitoring)
│   └── RDS (Persistent Storage)
└── Fluentd (Centralized Logging)

Tổng quan Sơ đồ Kiến trúc

(1) Developer Workstations (Máy trạm của Lập trình viên) Lập trình viên commit code lên kho lưu trữ GitHub.

(2) Continuous Integration (Tích hợp liên tục)

  • Jenkins lấy code mới nhất từ GitHub.
  • Build và test ứng dụng.
  • Tạo Docker image và đẩy lên Amazon ECR.

(3) Infrastructure as Code (Hạ tầng dưới dạng mã)

  • Terraform cấp phát hạ tầng AWS:
    • VPC
    • IAM Roles và Policies (Quyền và Chính sách IAM)
    • EKS Cluster
    • RDS

(4) Continuous Deployment (Triển khai liên tục)

  • Jenkins triển khai Docker image lên EKS.
  • Istio quản lý lưu lượng giữa các microservices.

(5) Service Mesh

  • Istio cung cấp quản lý lưu lượng (traffic management), bảo mật và khả năng quan sát (observability).
  • Ingress Gateway quản lý truy cập bên ngoài.

(6) Monitoring and Logging (Giám sát và Ghi log)

  • Prometheus thu thập metrics.
  • Grafana trực quan hóa metrics.
  • Fluentd tập trung log.
  • Alertmanager tích hợp với Prometheus để cảnh báo.

(7) Continuous Feedback (Phản hồi liên tục)

  • Alertmanager gửi thông báo.
  • Jenkins cung cấp phản hồi cho lập trình viên.

Các Thành phần Sơ đồ

  • GitHub: Quản lý phiên bản và kho lưu trữ mã nguồn.
  • Jenkins: Máy chủ CI/CD dùng để tự động hóa.
  • Docker: Công cụ container hóa.
  • Terraform: Cấp phát hạ tầng.
  • Amazon ECR: Kho lưu trữ Docker image.
  • Amazon EKS: Dịch vụ Kubernetes.
  • Istio: Quản lý service mesh.
  • Prometheus & Grafana: Bộ công cụ giám sát.
  • Fluentd: Giải pháp ghi log tập trung.
  • Alertmanager: Quản lý các cảnh báo.
  • Amazon CloudWatch: Dịch vụ ghi log và giám sát.

Luồng Kiến trúc

  1. Code Commit: Các lập trình viên đẩy (upload) code lên GitHub.
  2. CI Pipeline: Jenkins (công cụ CI/CD) build, test và tạo các Docker image.
  3. Image Push: Jenkins đẩy các Docker image lên Amazon ECR.
  4. Infrastructure Deployment: Terraform cấp phát hạ tầng AWS của chúng ta tại đây.
  5. CD Pipeline: Jenkins triển khai các ứng dụng sử dụng Istio để quản lý định tuyến.
  6. Service Mesh Management: Istio tại đây xử lý giao tiếp và giám sát.
  7. Monitoring & Logging: Prometheus thu thập các metrics; trong khi Fluentd chuyển tiếp các log đến CloudWatch.
  8. Alerting: Công cụ Alertmanager gửi các cảnh báo dựa trên metrics.

4. Step by Step

Hạ tầng dưới dạng mã (Infrastructure as Code) với Terraform

Bước 1 — Thiết lập VPC và Mạng của chúng ta

Tạo một thư mục mới cho các file Terraform của bạn:

mkdir advanced-aws-devops-project
cd advanced-aws-devops-project

Khởi tạo dự án Terraform của chúng ta:

terraform init

Tiếp theo, chúng ta sẽ tạo một file main.tf với nội dung sau. Nó định nghĩa VPC, các subnet và các thành phần mạng của chúng ta:

provider "aws" {
    region = "us-west-2"
  }

resource "aws_vpc" "main_vpc" {
    cidr_block = "10.0.0.0/16"
    enable_dns_support = true
    enable_dns_hostnames = true
    tags = {
      Name = "advanced-devops-vpc"
    }
  }
  resource "aws_subnet" "public_subnet" {
    vpc_id            = aws_vpc.main_vpc.id
    cidr_block        = "10.0.1.0/24"
    map_public_ip_on_launch = true
    availability_zone = "us-west-2a"
    tags = {
      Name = "public-subnet"
    }
  }
  resource "aws_subnet" "private_subnet" {
    vpc_id            = aws_vpc.main_vpc.id
    cidr_block        = "10.0.2.0/24"
    availability_zone = "us-west-2b"
    tags = {
      Name = "private-subnet"
    }
  }
  resource "aws_internet_gateway" "igw" {
    vpc_id = aws_vpc.main_vpc.id
    tags = {
      Name = "main-igw"
    }
  }
  resource "aws_route_table" "public_route_table" {
    vpc_id = aws_vpc.main_vpc.id
    route {
      cidr_block = "0.0.0.0/0"
      gateway_id = aws_internet_gateway.igw.id
    }
    tags = {
      Name = "public-route-table"
    }
  }
  resource "aws_route_table_association" "public_subnet_association" {
    subnet_id      = aws_subnet.public_subnet.id
    route_table_id = aws_route_table.public_route_table.id
  }

Tiếp theo, chúng ta sẽ áp dụng cấu hình terraform của mình:

terraform apply

Bước 2 — Các quyền và chính sách IAM

Đối với bước 2, hãy tạo một file iam.tf nơi chúng ta sẽ định nghĩa các quyền và chính sách IAM cho EKS, RDS và các dịch vụ AWS khác mà chúng ta sẽ sử dụng:

resource "aws_iam_role" "eks_role" {
    name = "eks_role"
    assume_role_policy = jsonencode({
      "Version": "2012-10-17",
      "Statement": [{
        "Action": "sts:AssumeRole",
        "Effect": "Allow",
        "Principal": {
          "Service": "eks.amazonaws.com"
        }
      }]
    })
  }

resource "aws_iam_role_policy_attachment" "eks_policy_attachment" {
    role       = aws_iam_role.eks_role.name
    policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
  }

resource "aws_iam_role" "rds_role" {
    name = "rds_role"
    assume_role_policy = jsonencode({
      "Version": "2012-10-17",
      "Statement": [{
        "Action": "sts:AssumeRole",
        "Effect": "Allow",
        "Principal": {
          "Service": "rds.amazonaws.com"
        }
      }]
    })
  }

resource "aws_iam_role_policy_attachment" "rds_policy_attachment" {
    role       = aws_iam_role.rds_role.name
    policy_arn = "arn:aws:iam::aws:policy/AmazonRDSFullAccess"
  }

Một lần nữa, chúng ta áp dụng cấu hình IAM role:

terraform apply

Bước 3 — Tạo EKS Cluster của chúng ta

Để làm điều này, hãy thêm nội dung sau vào file main.tf để tạo một EKS cluster với các node group tự động mở rộng (auto-scaling):

module "eks" {
    source          = "terraform-aws-modules/eks/aws"
    cluster_name    = "advanced-eks-cluster"
    cluster_version = "1.24"
    vpc_id          = aws_vpc.main_vpc.id
    subnets         = [aws_subnet.public_subnet.id, aws_subnet.private_subnet.id]
    node_groups = {
      eks_nodes = {
        desired_capacity = 3
        max_capacity     = 5
        min_capacity     = 2
        instance_type = "t3.medium"
        key_name      = "your-key-pair"
        tags = {
          Name = "advanced-eks-node"
        }
      }
    }
  }

Bây giờ chúng ta áp dụng cấu hình mới để tạo EKS của mình:

terraform apply

Bước 4: Tích hợp với RDS để lưu trữ dữ liệu bền vững

Tuyệt vời cho đến bây giờ. Bây giờ chúng ta hãy tạo một RDS instance để lưu trữ dữ liệu bền vững trong file rds.tf của chúng ta:

resource "aws_db_instance" "db_instance" {
    allocated_storage    = 20
    engine               = "mysql"
    engine_version       = "8.0"
    instance_class       = "db.t3.micro"
    name                 = "microservicesdb"
    username             = "admin"
    password             = "password"
    parameter_group_name = "default.mysql8.0"
    skip_final_snapshot  = true
    vpc_security_group_ids = [aws_security_group.eks_sg.id]
    db_subnet_group_name   = aws_db_subnet_group.rds_subnet_group.name
  }
  resource "aws_db_subnet_group" "rds_subnet_group" {
    name       = "rds-subnet-group"
    subnet_ids = [aws_subnet.private_subnet.id]
    tags = {
      Name = "RDS Subnet Group"
    }
  }

Một lần nữa chúng ta áp dụng điều này và tạo RDS:

terraform apply

Triển khai Jenkins trong cấu hình HA (Tính sẵn sàng cao)

Bước 5: Thiết lập Jenkins trên EC2 (với Auto-Scaling)

Khởi chạy Jenkins trên một EC2 instance với Auto-Scaling được bật:

resource "aws_launch_configuration" "jenkins_lc" {
    image_id      = "ami-0abcdef1234567890"
    instance_type = "t3.medium"
    key_name      = "your-key-pair"
    security_groups = [aws_security_group.jenkins_sg.id]
    lifecycle {
      create_before_destroy = true
    }
    user_data = <<-EOF
              #!/bin/bash
              sudo yum update -y
              sudo yum install -y java-1.8.0-openjdk
              sudo wget -O /etc/yum.repos.d/jenkins.repo \
                https://pkg.jenkins.io/redhat-stable/jenkins.repo
              sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
              sudo yum install -y jenkins
              sudo systemctl start jenkins
              sudo systemctl enable jenkins
              EOF
  }

  resource "aws_autoscaling_group" "jenkins_asg" {
    launch_configuration = aws_launch_configuration.jenkins_lc.id
    min_size             = 2
    max_size             = 4
    desired_capacity     = 2
    vpc_zone_identifier  = [aws_subnet.public_subnet.id]
    tags = [
      {
        key                 = "Name"
        value               = "Jenkins Instance"
        propagate_at_launch = true
      },
    ]
  }

Bây giờ chúng ta hãy áp dụng các thay đổi mới của mình:

terraform apply

Lưu ý: Vui lòng cập nhật URL Jenkins mà bạn đang sử dụng ở đây trong trường hợp nó không hoạt động với bạn, phiên bản Jenkins có thể đã thay đổi hoặc cập nhật.

Bước 6: Cấu hình kiến trúc Jenkins Master-Slave

Chúng ta sẽ sử dụng kiến trúc Jenkins Master-Slave. Nó cho phép chúng ta phân phối khối lượng công việc xây dựng, kiểm thử và triển khai ứng dụng trên nhiều máy. Kiến trúc độc đáo này giúp ích rất nhiều, đầu tiên nó nâng cao hiệu suất và cũng cung cấp việc sử dụng tài nguyên tốt hơn, đặc biệt trong các môi trường quy mô lớn. Dưới đây là hướng dẫn chi tiết để thiết lập Jenkins trong kiến trúc này.

Yêu cầu tiên quyết

  • Jenkins Master Node (Node chính Jenkins): Máy chủ Jenkins chính (còn gọi là bộ điều khiển), sẽ điều phối các tác vụ build và phân phối chúng đến các node agent.
  • Jenkins Agent Nodes (Các Node Agent Jenkins): Đây là các máy chủ bổ sung (slave) thực thi các tác vụ build được gán bởi node Jenkins master.

Bước 6.1: Thiết lập Jenkins Master

Thông thường, chúng ta đã thiết lập Jenkins trên một EC2 instance trong các bước trước. Instance này sẽ đóng vai trò là Jenkins master của chúng ta. Để tiếp tục, hãy đảm bảo các điều sau đã sẵn sàng:

  • Java đã được cài đặt: Jenkins yêu cầu Java để chạy. Xác minh rằng Java đã được cài đặt:

    java -version

    Nếu chưa được cài đặt, bạn có thể thực hiện bằng lệnh dưới đây:

    sudo yum install -y java-1.8.0-openjdk
  • Cài đặt Jenkins: Bây giờ hãy truy cập nó. Jenkins của chúng ta sẽ đang chạy và có thể truy cập được qua trình duyệt web. Xác nhận điều này bằng cách điều hướng đến `http://

    :8080` trong trình duyệt của bạn.

Bước 6.2: Chuẩn bị Jenkins Agent Nodes

Như đã đề cập trước đó, chúng ta cần thêm các EC2 instance sẽ đóng vai trò là Jenkins agent của chúng ta. Đây là cách thực hiện:

  1. Khởi chạy EC2 Instances cho Jenkins Agents:

    • Sử dụng Bảng điều khiển quản lý AWS (AWS Management Console), khởi chạy các EC2 instance mới. Bạn có thể chọn Amazon Linux 2 AMI (hoặc bất kỳ bản phân phối Linux nào khác).
    • Đảm bảo rằng các instance này có đủ tài nguyên (ví dụ: t2.micro) và nằm trong cùng VPC với Jenkins master.
  2. Security Groups (Nhóm bảo mật):

    • Đảm bảo rằng các nhóm bảo mật cho phép truy cập SSH từ node Jenkins master, bằng cách thêm nó vào nhóm bảo mật.
    • Ngoài ra, cho phép giao tiếp trên các cổng cần thiết cho giao tiếp giữa Jenkins agent và master (cổng SSH mặc định 22).
  3. Cài đặt Java trên Agent Nodes:

    • Bây giờ chúng ta sẽ SSH vào từng node agent và cài đặt Java:
    sudo yum update -y
    sudo yum install -y java-1.8.0-openjdk
  4. Tạo người dùng Jenkins trên Agent Nodes:

    • Để sử dụng Jenkins đầy đủ trên máy chủ này, chúng ta cần tạo một người dùng cho nó.
    sudo useradd jenkins

    Thiết lập quyền truy cập SSH cho người dùng này, để Jenkins master có thể kết nối:

    sudo mkdir /home/jenkins/.ssh
    sudo chown jenkins:jenkins /home/jenkins/.ssh
    sudo chmod 700 /home/jenkins/.ssh

    Chúng ta sẽ cần các khóa SSH, vì vậy hãy sao chép khóa public SSH từ Jenkins master vào file /home/jenkins/.ssh/authorized_keys của mỗi agent.

  5. Cài đặt Jenkins Agent trên Agent Nodes:

    • Tải xuống Jenkins agent (còn gọi là agent.jar) từ trang web Jenkins.
    • Chuyển file agent.jar này sang mỗi node agent, đặt nó vào một thư mục như /home/jenkins.

Bước 6.3: Cấu hình Jenkins Master của chúng ta để sử dụng Agents

  1. Thêm các Node mới trong Jenkins:

    • Trên bảng điều khiển Jenkins, chúng ta sẽ đi tới Manage Jenkins > Manage Nodes and Clouds > New Node.
    • Bây giờ chúng ta có thể nhập tên cho node mới (ví dụ: Agent-1), chọn Permanent Agent, và nhấp OK.
  2. Cấu hình Cài đặt Node:

    • Remote root directory (Thư mục gốc từ xa): Chúng ta sẽ chỉ định thư mục trên agent nơi Jenkins của chúng ta sẽ hoạt động, ví dụ: /home/jenkins.
    • Labels (Nhãn): Đề cập đến việc gán nhãn cho node để dễ dàng phân bổ công việc (ví dụ: linux-agent).
    • Launch method (Phương pháp khởi chạy): Chọn Launch agents via SSH.
    • Host (Máy chủ): Tại đây chúng ta nhập địa chỉ IP private của node agent.
    • Credentials (Thông tin xác thực): Thêm thông tin xác thực SSH (tên người dùng và khóa private) cho người dùng jenkins.

    Kiểm tra Kết nối của chúng ta:

    • Đầu tiên nhấp vào Save và sau đó > Launch agent via SSH.
    • Khi chúng ta làm điều này, Jenkins sẽ cố gắng kết nối với node agent qua SSH. Nếu thành công, bạn sẽ thấy trạng thái của agent chuyển thành “Connected”.
  3. Các Agent bổ sung:

    • Chúng ta có thể đơn giản lặp lại các bước trên để cấu hình bất kỳ Jenkins agent bổ sung nào.

Bước 6.4: Cấu hình các Jenkins Job của chúng ta để sử dụng các Node/Agent cụ thể

Bây giờ chúng ta đã kết nối Jenkins master của mình với các node agent, chúng ta có thể cấu hình các job để chạy trên các agent cụ thể:

  1. Tạo hoặc Cấu hình một Jenkins Job:

    • Đi tới New Item trên bảng điều khiển Jenkins hoặc chọn một job hiện có.
  2. Chỉ định Sử dụng Node:

    • Bây giờ, trong cấu hình job, chúng ta sẽ tìm kiếm phần Restrict where this project can be run. Tên của nó nói rõ chức năng của nó.
    • Tất cả những gì còn lại là nhập nhãn của agent (ví dụ: linux-agent) nơi bạn muốn job chạy.
  3. Lưu và Build:

    • Chúng ta đã hoàn thành, vì vậy chúng ta lưu cấu hình job và > kích hoạt một bản build.
    • Job này bây giờ sẽ thực thi trên node Jenkins agent được chỉ định của chúng ta.

Bước 6.5: Giám sát và Quản lý Jenkins Agents

  • Node Monitoring (Giám sát Node):

    • Như chúng ta đã biết. Jenkins cung cấp giám sát tích hợp cho từng node agent. Xem điều này bằng cách điều hướng đến Manage Jenkins > Manage Nodes and Clouds, nơi chúng ta có thể thấy trạng thái, thời gian rảnh và tải cho mỗi agent.
  • Scaling Agents (Mở rộng quy mô Agent):

    • Đối với các môi trường đám mây quy mô lớn, chúng ta có thể cấu hình tính năng tự động mở rộng (auto-scaling) cho các node agent của mình bằng cách sử dụng AWS Auto Scaling Groups. Điều này cho phép Jenkins tự động mở rộng số lượng agent dựa trên khối lượng công việc.
  • Agent Availability (Tính sẵn có của Agent):

    • Điều này đảm bảo các agent luôn khả dụng bằng cách cấu hình chúng với các kiểm tra sức khỏe mạnh mẽ (như giám sát CPU, bộ nhớ và mức sử dụng đĩa). Tích hợp với các công cụ giám sát như CloudWatch hoặc Prometheus có thể giúp chúng ta tự động hóa điều này.

Xây dựng và Docker hóa Microservices

Bước 7: Tổng quan Ứng dụng Microservices

Đầu tiên chúng ta sẽ giả định rằng chúng ta có một ứng dụng microservices với các thành phần sau:

  • User Service (Dịch vụ Người dùng): Quản lý xác thực người dùng và hồ sơ.
  • Order Service (Dịch vụ Đơn hàng): Xử lý và quản lý đơn hàng.
  • Payment Service (Dịch vụ Thanh toán): Tích hợp với các cổng thanh toán để xử lý thanh toán.

Tạo Dockerfiles cho mỗi dịch vụ:

  • Dockerfile — User Service:

    FROM openjdk:8-jdk-alpine
    VOLUME /tmp
    ARG JAR_FILE=target/user-service.jar
    COPY ${JAR_FILE} user-service.jar
    ENTRYPOINT ["java","-jar","/user-service.jar"]
  • Dockerfile — Order Service:

    FROM openjdk:8-jdk-alpine
    VOLUME /tmp
    ARG JAR_FILE=target/order-service.jar
    COPY ${JAR_FILE} order-service.jar
    ENTRYPOINT ["java","-jar","/order-service.jar"]
  • Dockerfile — Payment Service:

    FROM openjdk:8-jdk-alpine
    VOLUME /tmp
    ARG JAR_FILE=target/payment-service.jar
    COPY ${JAR_FILE} payment-service.jar
    ENTRYPOINT ["java","-jar","/payment-service.jar"]

Bây giờ chúng ta cuối cùng có thể build và đẩy các Docker image của mình lên Amazon ECR:

# Build các docker image của chúng ta
docker build -t user-service ./user-service
docker build -t order-service ./order-service
docker build -t payment-service ./payment-service

# Đẩy các image lên ECR
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin 
<aws_account_id>.dkr.ecr.us-west-2.amazonaws.com
docker tag user-service:latest 
<aws_account_id>.dkr.ecr.us-west-2.amazonaws.com/user-service:latest
docker push 
<aws_account_id>.dkr.ecr.us-west-2.amazonaws.com/user-service:latest

Triển khai Service Mesh với Istio

Bước 8: Cài đặt Istio trên EKS

Đầu tiên chúng ta cần cài đặt Istio trên EKS cluster của mình bằng cách sử dụng Helm:

helm repo add istio https://istio-release.storage.googleapis.com/charts
helm install istio-base istio/base -n istio-system --create-namespace
helm install istiod istio/istiod -n istio-system
helm install istio-ingress istio/gateway -n istio-system

Bước 9: Cấu hình Quản lý Traffic, Bảo mật và Khả năng quan sát

Bây giờ chúng ta hãy định nghĩa VirtualServiceDestinationRule của Istio cho việc quản lý traffic:

#virtualservice.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: user-service
spec:
  hosts:
    - user-service
  http:
    - route:
        - destination:
            host: user-service
            subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: user-service
spec:
  host: user-service
  subsets:
    - name: v1
      labels:
        version: v1

Tiếp theo, chúng ta sẽ áp dụng các chính sách bảo mật bằng cách sử dụng Mutual TLS (mTLS) của Istio:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: istio-system
spec:
  mtls:
    mode: STRICT

Bạn đã làm rất tốt khi đi đến đây.

Chúng ta cũng sẽ cần bật khả năng quan sát (observability) bằng cách tích hợp telemetry của Istio với Prometheus và Grafana. Chúng ta sẽ làm điều đó ở bước 13.

Thiết lập Jenkins CI/CD Pipeline

Bước 10: Tích hợp GitHub, Jenkins, Docker và EKS

Để làm điều này, chúng ta sẽ sử dụng một Jenkinsfile để tự động hóa quá trình build, test và triển khai:

pipeline {
    agent any
    stages {
      stage('Checkout') {
        steps {
          git 'https://github.com/your-repo/microservices-app.git'
        }
      }
      stage('Build') {
        steps {
          sh 'mvn clean package'
        }
      }
      stage('Docker Build & Push') {
        steps {
          script {
            docker.build("user-service:latest").push("${env.BUILD_TAG}")
          }
        }
      }
      stage('Deploy to EKS') {
        steps {
          script {
            sh 'kubectl apply -f k8s/deployment.yaml'
            sh 'kubectl apply -f k8s/service.yaml'
          }
        }
      }
    }
  }

Bước 11: Triển khai Blue-Green Deployments

1ef390ad-9d54-4340-9b52-f1869d9a28b5

Bây giờ chúng ta sẽ định nghĩa phương pháp triển khai của mình. Đối với kịch bản này, chúng ta sẽ chọn chiến lược triển khai blue-green:

#user-service-green.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service-green
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
      version: green
  template:
    metadata:
      labels:
        app: user-service
        version: green
    spec:
      containers:
      - name: user-service
        image: 
<aws_account_id>.dkr.ecr.us-west-2.amazonaws.com/user-service:green
        ports:
        - containerPort: 8080

Nếu bạn chưa từng nghe về nó, vui lòng nhấp vào đây để đọc thêm. Bây giờ chúng ta đã có file k8s/user-service-green.yaml sẵn sàng, hãy áp dụng nó cũng như file k8s/virtualservice.yaml của chúng ta.

kubectl apply -f k8s/user-service-green.yaml
kubectl apply -f k8s/virtualservice.yaml

Bước 12: Tự động hóa Canary Deployments bằng Istio

Ở bước này, chúng ta sẽ triển khai chiến lược canary deployment trong Istio VirtualService của bạn:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: user-service
spec:
  hosts:
    - user-service
  http:
    - route:
        - destination:
            host: user-service
            subset: v1
          weight: 90
        - destination:
            host: user-service
            subset: v2
          weight: 10

Giám sát, Ghi log và Cảnh báo

2db1f68d-7afa-4fbf-a528-476141e19edc

Bước 13: Thiết lập Prometheus và Grafana

Cài đặt Prometheus và Grafana qua Helm:

helm install prometheus prometheus-community/prometheus
helm install grafana grafana/grafana

Tiếp theo, chúng ta cần truy cập grafana (thông qua URL) và thêm Prometheus làm nguồn dữ liệu. Sau đó chúng ta có thể import các dashboard của Istio để giám sát. Hãy thực hiện điều đó.

Tiếp theo chúng ta sẽ cấu hình FluentD cho việc ghi log tập trung.

Bước 14: Cấu hình Fluentd cho việc ghi log tập trung

Thiết lập Fluentd DaemonSet trên EKS cluster của chúng ta để tổng hợp log từ tất cả các microservices:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
spec:
  selector:
    matchLabels:
      app: fluentd
  template:
    metadata:
      labels:
        app: fluentd
  spec:
    containers:
    - name: fluentd
      image: fluent/fluentd-kubernetes-daemonset:v1.11
      env:
        - name: FLUENT_ELASTICSEARCH_HOST
          value: "elasticsearch"
        - name: FLUENT_ELASTICSEARCH_PORT
          value: "9200"
      volumeMounts:
      - name: varlog
        mountPath: /var/log
      - name: varlibdockercontainers
        mountPath: /var/lib/docker/containers
        readOnly: true

Bước 15: Thiết lập Alertmanager để Phản ứng sự cố

Đây là bước cuối cùng trong dự án của chúng ta. Như chúng ta đã nói, chúng ta cần thiết lập các cảnh báo cho việc quản lý sự cố. Để làm điều đó, chúng ta sẽ cấu hình Prometheus Alertmanager để gửi cảnh báo dựa trên các metrics và ngưỡng. Bạn có thể sử dụng file cấu hình mẫu của mình dưới đây:

global:
  smtp_smarthost: 'smtp.gmail.com:587'
  smtp_from: 'alertmanager@example.com'
  smtp_auth_username: 'example@gmail.com'
  smtp_auth_password: 'password'
route:
  receiver: 'email-alert'
receivers:
- name: 'email-alert'
  email_configs:
  - to: 'your-email@example.com'

Bước bổ sung dành cho bạn

Là một bước bổ sung, hãy thử tích hợp Alertmanager với Slack để nhận thông báo sự cố theo thời gian thực. Mình không đưa vào dự án này nhưng mình sẽ đưa vào các dự án tiếp theo (Hãy theo dõi để biết thêm).

Kết luận

Đây là một bài viết dài và chi tiết và mình cũng có tham khảo rất nhiều nguồn đặc biệt trên Medium nguồn mà chắc mọi người đều biết. Kết hợp một kiến trúc đa dịch vụ, các pipeline Jenkins CI/CD, Docker, KubernetesIstio service mesh. Quá trình từng bước đã bao gồm mọi thứ chúng ta cần làm. Từ cấp phát hạ tầng, triển khai tự động, giám sát, ghi log, cho đến cảnh báo. Mình tin rằng dự án này đã cung cấp cho bạn (cũng như mình) một hướng dẫn toàn diện mà tất cả các kỹ sư Cloud & DevOps có thể làm theo. Thiết lập chúng ta đã sử dụng đảm bảo HA (tính sẵn sàng cao), khả năng mở rộng, bảo mật, cũng như khả năng quan sát (observability), biến nó thành một giải pháp thực sự mạnh mẽ để quản lý microservices trong môi trường cloud-native.

Article Thumbnail
Datadog Webinar: Modernize AWS Logs at Scale
Chia sẻ bài viết:
Theo dõi
Thông báo của
0 Góp ý
Được bỏ phiếu nhiều nhất
Mới nhất Cũ nhất
Phản hồi nội tuyến
Xem tất cả bình luận