HƯỚNG DẪN CÁC BƯỚC PHÁT TRIỂN HỆ THỐNG MICROSERVICE VỚI DOCKER

17/06/2020 947
CODEWELL

Trước khi Microservice ra đời, chúng ta phải thường xuyên làm việc với kiến trúc nguyên khối – Monolith. Một vấn đề phổ biến với Monolith là khi có bất kỳ thay đổi nhỏ nào, nhà phát triển cũng phải tốn công sức xây dựng và triển khai lại toàn bộ ứng dụng. Tuy nhiên, vấn đề này sẽ được giải quyết triệt để với Microservice. Vậy Microservice là gì? Cách xây dựng hệ thống Microservice gồm các bước nào? Hãy cùng chúng tôi khám phá trong bài viết này nhé!

1. Giới thiệu về Microservice

Microservices là một giải pháp kiến trúc cho phép chia một hệ thống lớn thành một vài các component độc lập về phát triển, test và deploy. Một ứng dụng được phát triển dựa trên kiến trúc microservice bao gồm các hệ thống con được phân tán, tức là các phần của ứng dụng đó có thể được phát triển trên các ngôn ngữ khác nhau và được triển khai trên các máy chủ khác nhau.

2. Kiến trúc hệ thống của Microservice

Để hiểu rõ về Microservices, chúng ta sẽ khảo sát hệ thống Microservice sau:

ảnh kiến trúc hệ thống microservice

Như sơ đồ kiến trúc trên, ta có thể thấy kiến trúc của hệ thống Microservice có thành phần chính là service registry, các service và Gateway.

 

1. Service registry:

Nơi để lưu trữ thông tin của các service là số lượng được triển khai, phiên bản, tình trạng deploy, … Mỗi service được định danh bởi một tên gọi cụ thể để các service có thể gọi lẫn nhau dễ dàng khi mà mỗi lần deploy IP động của service thay đổi.

 

2. Service:

Mỗi client service chỉ thực hiện duy nhất một nghiệp vụ nào đó trong hệ thống như thanh toán, tài khoản, thông báo, xác thực, cấu hình, … Mỗi service là độc lập trong kiến trúc Microservice.

 

3. Gateway – Zuul:

Gateway là gì?

Khi chúng ta gọi đến bất kỳ service nào từ browser, chúng ta không thể gọi trực tiếp bằng tên của chúng như ở trên Team server đã làm bởi vì những tên service như vậy phải được bí mật và chỉ sử dụng trong nội bộ các service với nhau.

Nếu chúng ta có nhiều instance của một service, mỗi instance lại sử dụng một port khác nhau. Vậy làm thế nào chúng ta có thể gọi tất cả các service từ browser và phân tán những request đến các instance đó thông qua các cổng khác nhau? Câu trả lời là sử dụng một Gateway.

Một gateway là một entry point đơn trong hệ thống, được dùng để handle các request bằng cách định tuyến chúng đến các service tương ứng. Nó cũng có thể được dùng để xác thực, giám sát và làm nhiều việc khác.

Zuul là gì?

Nó là một proxy, gateway và một lớp trung gian giữa user và các service của bạn. Eureka server đã giải quyết vấn đề đặt tên cho từng service thay vì dùng địa chỉ IP của chúng. Tuy nhiên một service vẫn có thể có nhiều instance và chúng sẽ chạy trên các cổng khác nhau. Do đó, nhiệm vụ của Zuul sẽ là:

  • Map giữa một prefix path và một service (team-service). Nó sử dụng Eureka server để định tuyến các service được request.
  • Giúp cân bằng tải giữa các instance của một service.
  • Filter request, thêm xác thực,…

Như vậy, chúng ta đã dựng xong bộ khung cho hệ thống microservice, gồm một service discovery (Eureka server), hai service (Member và Team), một cổng gateway (Zuul).

3. Bài toán thực tế với Microservice

Để có thể hình dung rõ hơn các bước phát triển một hệ thống sử dụng kiến trúc Microservice, chúng ta sẽ thực hành giải quyết một bài toán liên quan đến việc quản lý nhân sự trong công ty.  Ví dụ: chúng ta cần lấy thông tin nhân viên để xác định họ thuộc bộ phận nào?  Bộ phận đó có bao nhiêu thành viên, gồm những ai…

microservice các bước phát triển

Bước 1:

Môi trường / công cụ cần chuẩn bị:

Sẽ tạo 1 Eureka Server, 1 Zuul (Gateway), 2 Service (Member, Team)

Bước 2:

Truy cập Link sau để tạo Project

  • Tạo Project: Eureka Server

Thiết lập như cấu hình trong ảnh sau đó ấn GENERATE

Ảnh 1 microservice

 

  • Tạo Project: Zuul Service như cấu hình sau:

Ảnh 2 microservice

  • Tạo Project: Team Service như cấu hình sau:ảnh 3 microservice

  • Tạo Project: Member Service như cấu hình sau:

Ảnh 4 microservice

Sau khi tải về ta có các file như sau:

Ảnh 5 microservice

Giải nén ra:

Ảnh 6 microservice

Bật IDE import tất cả project trên vào

ảnh 7 microservice

Bước 3:

Sửa code trong các Project

  • Project spring-eureka-server:

Chúng ta sẽ khai báo đây là một Eureka server bằng annotation @EnableEurekaServer

Các bạn sửa file sau thành: spring-eureka-server\src\main\java\com\eureka\server\main\SpringEurekaServerApplication.java

package com.eureka.server.main;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer

@SpringBootApplication

public class SpringEurekaServerApplication {

 

       public static void main(String[] args) {

              SpringApplication.run(SpringEurekaServerApplication.class, args);

       }

 

}

 

Tiếp theo sửa file: spring-eureka-server\src\main\resources\application.properties

# Give a name to the eureka server

spring.application.name=eureka-server

 

# default port for eureka server

server.port=8761

 

# eureka by default will register itself as a client. So, we need to set it to false.

# What's a client server? See other microservices (student, auth, etc).

eureka.client.register-with-eureka=false

eureka.client.fetch-registry=false

Với cấu hình này eureka-server sẽ chạy trên port 8761

 

  • Project spring-eureka-zuul:

Chúng ta sẽ khai báo đây là một Eureka client và Zuul bằng annotation @EnableEurekaClient, @EnableZuulProxy

Các bạn sửa file sau: spring-eureka-zuul\src\main\java\com\eureka\zuul\main\SpringEurekaZuulApplication.java

package com.eureka.zuul.main;

 

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

 

@SpringBootApplication

@EnableEurekaClient

@EnableZuulProxy

public class SpringEurekaZuulApplication {

 

       public static void main(String[] args) {

             SpringApplication.run(SpringEurekaZuulApplication.class, args);

       }

 

}

Vì zuul là Gateway nên khi truy xuất dữ liệu vào Member hoặc Team thì sẽ phải gọi qua Zuul.

Để định nghĩa các service trong hệ thống của mình, cụ thể trong bài này có 2 service là Member và Team, chúng ta phải khai path và service-id như sau:

zuul.routes.member-service.path=/member/**

zuul.routes.member-service.service-id=member-service

 

zuul.routes.team-service.path=/team/**

zuul.routes.team-service.service-id=team-service

Cụ thể, sửa file với nội dung sau: spring-eureka-zuul\src\main\resources\application.properties

server.port=8762

spring.application.name=zuul-server

eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

 

# A prefix that can added to beginning of all requests.

#zuul.prefix=/api

 

# Disable accessing services using service name (i.e. gallery-service).

# They should be only accessed through the path defined below.

# Link: https://stackoverflow.com/questions/46317388/zuul-service-name-exposed-instead-of-route-path-only

zuul.ignored-services=*

 

zuul.routes.member-service.path=/member/**

zuul.routes.member-service.service-id=member-service

 

zuul.routes.team-service.path=/team/**

zuul.routes.team-service.service-id=team-service

 

# Exclude authorization from sensitive headers

zuul.routes.auth-service.sensitive-headers=Cookie,Set-Cookie

zuul.ignored-headers=Access-Control-Allow-Credentials, Access-Control-Allow-Origin

 

  • Với Project spring-eureka-team:

Các bạn sửa file sau thành: spring-eureka-team\src\main\java\com\eureka\team\main\ SpringEurekaTeamApplication.java

package com.eureka.team.main;

 

import java.util.Arrays;

import java.util.List;

 

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RestController;

 

@SpringBootApplication

@EnableEurekaClient

public class SpringEurekaTeamApplication {

 

       public static void main(String[] args) {

             SpringApplication.run(SpringEurekaTeamApplication.class, args);

       }

 

}

 

@RestController

class TeamRestController {

 

       @RequestMapping(value = "list", method = RequestMethod.GET, produces = "application/json")

       public List<Team> getAll() {

             List<Team> teams = Arrays.asList(

new Team(1, "Team 1"),

new Team(2, "Team 2"),

new Team(3, "Team 3"));

             return teams;

       }

}

 

class Team {

       private Integer id;

       private String name;

 

       public Team(Integer id, String name) {

             this.id = id;

             this.name = name;

       }

 

       public Team() {

       }

 

       public Integer getId() {

             return id;

       }

 

       public void setId(Integer id) {

             this.id = id;

       }

 

       public String getName() {

             return name;

       }

 

       public void setName(String name) {

             this.name = name;

       }

}

 

Tiếp theo sửa file: spring-eureka-team\src\main\resources\application.properties

spring.application.name=team-service

server.port=8201

eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka

 

  • Với Project spring-eureka-member:

Các bạn sửa file sau thành: spring-eureka-member\src\main\java\com\eureka\member\main\ SpringEurekaMemberApplication

package com.eureka.member.main;

 

import java.util.Arrays;

import java.util.List;

 

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RestController;

 

@SpringBootApplication

@EnableEurekaClient

public class SpringEurekaMemberApplication {

 

       public static void main(String[] args) {

             SpringApplication.run(SpringEurekaMemberApplication.class, args);

       }

 

}

 

@RestController

class MemberRestController {

 

       @RequestMapping(value = "list", method = RequestMethod.GET, produces = "application/json")

       public List<Member> getMembers() {

             List<Member> members = Arrays.asList(

new Member(1, "Nguyen Van A "),

new Member(2, "Nguyen Van B "),

                    new Member(3, "Nguyen Van C "));

             return members;

       }

 

}

 

class Member {

 

       private Integer id;

       private String name;

 

       public Member(Integer id, String name) {

             this.id = id;

             this.name = name;

       }

 

       public Integer getId() {

             return id;

       }

 

       public void setId(Integer id) {

             this.id = id;

       }

 

       public String getName() {

             return name;

       }

 

       public void setName(String name) {

             this.name = name;

       }

}

 

Tiếp theo sửa file: spring-eureka-team\src\main\resources\application.properties

spring.application.name=member-service

server.port=8202

eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka

 

Bước 4:

Chạy lần lượt các service: spring-eureka-server, spring-eureka-zuul, spring-eureka-team, spring-eureka-member

ảnh 8 microservice

Để kiểm tra ứng dụng, hãy truy cập http://localhost:8761, đây là cổng của Eureka Server. Và bạn sẽ thấy các service đang chạy như sau:

ảnh 9 microservice

 

Tiếp theo chúng ta gọi đến service Member thông qua Zuul bằng đường dẫn

localhost:8762/member/list

Kết quả nhận được sẽ là danh sách Member:

ảnh 10 microservice

Truy cập tiếp đường dẫn: http://localhost:8762/team/list

Kết quả:

ảnh 11 microservice

Vậy là chúng ta đã xây dựng xong hệ thống microservice.

 

4. Ứng dụng Docker trong hệ thống Microservice

Điều gì sẽ xảy ra nếu như bạn không chỉ có một mà có đến hàng chục hoặc hàng trăm serive cần triển khai? Việc triển khai thủ công sẽ cực kỳ tốn thời gian. Câu trả lời cho bài toán này chính là ứng dụng Docker. Khi sử dụng Docker, chúng ta có thể dễ dàng tự động hóa việc deploy cho tất cả các service:

microservice-04

Các bước ứng dụng Docker như sau:

 

Bước 1:

Tạo file docker-compose.yml để ngang hàng với thư mục các Project java với nội dung:

version : "2.1"

services:

  eureka:

    image: microservice/server

    container_name: eureka

    build:

      context: .

      dockerfile: ./spring-eureka-server/Dockerfile

    hostname: eureka

    ports:

      - "8761:8761"

    networks:

      - microservicesnet

 

  zuul:

    image: microservice/zuul

    container_name: zuul

    build:

      context: .

      dockerfile: ./spring-eureka-zuul/Dockerfile

    ports:

     - "8762:8762"

    networks:

      - microservicesnet

 

  team:

    image: microservice/team

    container_name: team

    build:

      context: .

      dockerfile: ./spring-eureka-team/Dockerfile

    ports:

       - "8201:8201"

    networks:

      - microservicesnet

 

  member:

    image: microservice/member

    container_name: member

    build:

      context: .

      dockerfile: ./spring-eureka-member/Dockerfile

    ports:

       - "8202:8202"

    networks:

      - microservicesnet

 

networks:

  microservicesnet:

 

Bước 2:

Lần lượt tạo Dockerfile cho spring-eureka-server, spring-eureka-zuul, spring-eureka-team, spring-eureka-member. Đặt Dockerfile vào trong mỗi project.

  • Project spring-eureka-server:

FROM java:8

FROM maven:alpine

 

# image layer

WORKDIR /app/spring-eureka-server

# Image layer: with the application

COPY ./spring-eureka-server /app/spring-eureka-server

RUN mvn -v

RUN mvn clean install -DskipTests

ENTRYPOINT ["java","-jar","/app/spring-eureka-server/target/spring-eureka-server-0.0.1-SNAPSHOT.jar"]

 

  • Project spring-eureka-zuul:

FROM java:8

FROM maven:alpine

 

# image layer

WORKDIR /app/spring-eureka-zuul

 

# Image layer: with the application

COPY ./spring-eureka-zuul /app/spring-eureka-zuul

RUN mvn -v

RUN mvn clean install -DskipTests

ENTRYPOINT ["java", "-Deureka.client.serviceUrl.defaultZone=http://eureka:8761/eureka","-jar","/app/spring-eureka-zuul/target/spring-eureka-zuul-0.0.1-SNAPSHOT.jar"]

 

  • Project spring-eureka-team:

FROM java:8

FROM maven:alpine

 

# image layer

WORKDIR /app/spring-eureka-team

 

# Image layer: with the application

COPY ./spring-eureka-team /app/spring-eureka-team

RUN mvn -v

RUN mvn clean install -DskipTests

ENTRYPOINT ["java", "-Deureka.client.serviceUrl.defaultZone=http://eureka:8761/eureka","-jar","/app/spring-eureka-team/target/spring-eureka-team-0.0.1-SNAPSHOT.jar"]

 

  • Project spring-eureka-member:

FROM java:8

FROM maven:alpine

 

# image layer

WORKDIR /app/spring-eureka-member

 

# Image layer: with the application

COPY ./spring-eureka-member /app/spring-eureka-member

RUN mvn -v

RUN mvn clean install -DskipTests

ENTRYPOINT ["java", "-Deureka.client.serviceUrl.defaultZone=http://eureka:8761/eureka","-jar","/app/spring-eureka-member/target/spring-eureka-member-0.0.1-SNAPSHOT.jar"]

 

Bước 3:

Chạy thử. Thực hiện chạy docker compose để build image và container như sau: Mở cmd tại vị trí file docker-compose.yml gõ lệnh:                          docker-compose up    

Kết quả được như sau:

ảnh 12 microservice

Quá trình Docker Build Image và Container sẽ lâu, thời gian chờ sẽ phụ thuộc vào mạng và cấu hình máy.

Sau khi docker đã start hết các container chứa service của mình lên, chúng ta truy cập địa chỉ: http://localhost:8761 để kiểm tra các service đã hoạt động hay chưa. Nếu các service đã hoạt động như hình dưới, thì khi đó chương trình đã hoạt động tốt.

 

5. Lời kết

Vậy là chúng tôi đã giới thiệu với các bạn về Microservice, các bước triển khai một hệ thống Microservice, cũng như cách thức ứng dụng Docker với giải pháp kiến trúc này. Mong rằng các bạn đã có thêm kinh nghiệm để tự tin triển khai trong các dự án tương lai của mình.

Nguyễn Duy Quang & Nguyễn Văn Thành – CO-WELL Asia

===========================

Xem thêm các bài viết thú vị tại fanpage CO-WELL Asia