• Tidak ada hasil yang ditemukan

đại học quốc gia hà nội trường đại học công nghệ

N/A
N/A
Protected

Academic year: 2024

Membagikan "đại học quốc gia hà nội trường đại học công nghệ"

Copied!
83
0
0

Teks penuh

(1)

ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ

NGUYỄN TRỌNG HIẾU

XÂY DỰNG KIẾN TRÚC TRIỂN KHAI LIÊN TỤC CHO CÁC HỆ THỐNG DỰA TRÊN VI DỊCH VỤ

LUẬN VĂN THẠC SĨ KỸ THUẬT PHẦN MỀM

HÀ NỘI - 2018

(2)

ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ

NGUYỄN TRỌNG HIẾU

XÂY DỰNG KIẾN TRÚC TRIỂN KHAI LIÊN TỤC CHO CÁC HỆ THỐNG DỰA TRÊN VI DỊCH VỤ

Ngành: Công nghệ thông tin

Chuyên ngành: Kỹ thuật phần mềm Mã số: 8480103.01

LUẬN VĂN THẠC SĨ KỸ THUẬT PHẦN MỀM

NGƯỜI HƯỚNG DẪN KHOA HỌC: TS. VÕ ĐÌNH HIẾU

(3)

LỜI CAM ĐOAN

Tôi xin cam đoan rằng luận văn thạc sĩ Kĩ thuật phần mềm "Xây dựng kiến trúc triển khai liên tục cho các hệ thống dựa trên vi dịch vụ" là sản phẩm nghiên cứu khoa học của riêng cá nhân tôi, dưới sự giúp đỡ rất lớn của Giảng viên hướng dẫn là TS. Võ Đình Hiếu, không sao chép lại của người khác. Những điều được trình bày trong toàn bộ nội dung của luận văn này hoặc là của chính cá nhân tôi, hoặc là được tổng hợp từ nhiều nguồn tài liệu. Tất cả các tài liệu tham khảo đều có nguồn gốc rõ ràng và được trích dẫn hợp pháp.

Tôi xin hoàn toàn chịu trách nhiệm và chịu mọi hình thức kỷ luật theo quy định cho lời cam đoan của mình.

Hà nội, tháng 11 năm 2018 Học viên

Nguyễn Trọng Hiếu

(4)

LỜI CẢM ƠN

Trước tiên, tôi xin bày tỏ lòng biết ơn chân thành và sâu sắc đến thầy giáo, TS.

Võ Đình Hiếu - người đã dành nhiều tâm huyết, tận tình chỉ bảo và giúp đỡ tôi trong suốt quá trình bắt đầu thực hiện đề tài cho đến khi hoàn thành.

Tôi xin gửi lời cảm ơn chân thành tới các thầy cô giáo khoa Công nghệ thông tin, trường Đại học Công nghệ, Đại học Quốc gia Hà nội - nơi tôi đã theo học trong thời gian qua. Các thầy cô đã cung cấp cho tôi những kiến thức quý báu, tạo điều kiện tốt nhất cho tôi trong suốt quá trình học tập và nghiên cứu tại trường.

Cuối cùng, tôi xin chân thành cảm ơn những người thân trong gia đình, bạn bè cùng khóa, đồng nghiệp trong cơ quan đã giúp đỡ và tạo điều kiện cho tôi trong quá trình học tập và nghiên cứu thực hiện luận văn này.

Tuy rằng tôi đã cố gắng hết sức trong quá trình làm luận văn nhưng không thể tránh khỏi thiếu sót, tôi rất mong nhận được những góp ý của thầy cô và các bạn.

Hà nội, tháng 11 năm 2018 Học viên

Nguyễn Trọng Hiếu

(5)

MỤC LỤC

LỜI CAM ĐOAN --- 1

LỜI CẢM ƠN --- 1

BẢNG CÁC KÝ HIỆU VÀ CHỮ VIẾT TẮT --- 1

DANH MỤC HÌNH VẼ --- 1

DANH MỤC BẢNG BIỂU --- 1

MỞ ĐẦU --- 1

CHƯƠNG 1: KIẾN THỨC CƠ BẢN --- 4

1.1 Tính toán đám mây --- 4

1.1.1 Giới thiệu về tính toán đám mây --- 4

1.1.2 Sự phổ biến của ứng dụng dựa vào đám mây --- 5

1.2 Tích hợp, chuyển giao và triển khai liên tục --- 6

1.2.1 Tích hợp liên tục --- 6

1.2.2 Chuyển giao liên tục --- 7

1.2.3 Triển khai liên tục --- 8

1.3 Kiến trúc hệ thống --- 8

1.3.1 Kiến trúc một khối --- 9

1.3.2 Kiến trúc hướng dịch vụ --- 10

1.3.3 Kiến trúc vi dịch vụ --- 11

1.4 Các mô hình triển khai --- 13

1.4.1 Mô hình triển khai tùy biến --- 13

1.4.2 Mô hình không tùy biến kết hợp với Reverse Proxy --- 14

1.4.3 Mô hình không tùy biến với ứng dụng vi dịch vụ --- 15

1.5 Khái niệm Container --- 17

CHƯƠNG 2: YÊU CẦU CỦA HỆ THỐNG TRIỂN KHAI LIÊN TỤC --- 21

2.1 Yêu cầu về điều phối container --- 21

2.1.1 Khám phá dịch vụ --- 21

2.1.2 Bộ lập lịch --- 22

2.1.3 Điều phối container --- 23

2.2 Yêu cầu cho các nhà phát triển --- 24

2.2.1 Khả năng tự triển khai --- 24

2.2.2 Nhận được các thông tin về kết quả build --- 25

2.3 Yêu cầu về vận hành --- 25

2.3.1 Quản lý cấu hình --- 25

2.3.2 Thu thập và lưu trữ log --- 25

2.3.3 Giám sát và thông báo lỗi --- 26

2.3.4 Triển khai không bị gián đoạn và có khả năng đảo ngược phiên bản --- 27

2.3.5 Thiết kế mạng triển khai --- 27

CHƯƠNG 3: THIẾT KẾ HỆ THỐNG TRIỂN KHAI LIÊN TỤC --- 28

3.1 Luồng triển khai cơ bản --- 28

3.2 Phân tích và lựa chọn công nghệ --- 29

(6)

3.2.1 Hệ thống quản lý mã nguồn --- 29

3.2.2 Máy chủ CI và máy chủ triển khai --- 30

3.2.3 Công nghệ container --- 32

3.2.4 Nền tảng điều phối container --- 32

3.2.5 Kubernetes --- 36

3.2.6 Kênh thông báo --- 38

3.2.7 Hệ thống thu thập và quản lý log --- 39

3.2.8 Công nghệ giám sát hệ thống và cảnh báo --- 41

3.2.9 Giải pháp quản lý cấu hình --- 43

3.3 Luồng triển khai liên tục hoàn thiện --- 43

CHƯƠNG 4: CÀI ĐẶT VÀ ĐÁNH GIÁ --- 47

4.1 Cài đặt --- 47

4.1.1 Hệ thống vi dịch vụ mẫu --- 47

4.1.2 Cách thức tổ chức mã nguồn và quá trình build ảnh docker --- 48

4.1.3 Cài đặt môi trường sản phẩm --- 53

4.2 Đánh giá kết quả --- 58

KẾT LUẬN --- 61

TÀI LIỆU THAM KHẢO --- 63

PHỤ LỤC --- 65

(7)

BẢNG CÁC KÝ HIỆU VÀ CHỮ VIẾT TẮT

STT Thuật ngữ viết tắt Thuật ngữ đầy đủ

1 EFK Elasticsearch, Fluentd, Kibana

2 VPC Virtual Private Cloud

3 VM Virtual Machine

4 CI Continuous Integration

5 IaaS Infrastructure as a Service

6 PaaS Platform as a Service

7 SaaS Software as a Service

8 IAC Infrastructure as code

9 DNS Domain Name System

10 SOA Service Oriented Architecture

11 Container Công nghệ container, ảo hóa mức hệ

điều hành

(8)

DANH MỤC HÌNH VẼ

Hình 1.1: Các bước cơ bản trong tích hợp liên tục [5] ... 7

Hình 1.2: Bảng so sánh kiến trúc một khối, kiến trúc hướng dịch vụ và kiến trúc vi dịch vụ [5] ... 8

Hình 1.3: Kiến trúc một khối cho ứng dụng đặt hàng ... 9

Hình 1.4: Kiến trúc hướng dịch vụ cho ứng dụng đặt hàng ... 11

Hình 1.5: Kiến trúc vi dịch vụ cho ứng dụng đặt hàng ... 12

Hình 1.6: Mô hình triển khai không tùy biến - cập nhật ứng dụng [5] ... 14

Hình 1.7: Mô hình triển khai không tùy biến - cấu hình reverse proxy khi cập nhật [5] ... 15

Hình 1.8: Mô hình triển khai không tùy biến với vi dịch vụ - cập nhật dịch vụ [5] ... 16

Hình 1.9: Mô hình triển khai không tùy biến với vi dịch vụ - cấu hình reverse proxy [5] ... 16

Hình 1.10: Công nghệ container ... 17

Hình 1.11: Khác biệt giữa container và máy ảo ... 18

Hình 1.12: Kiến trúc Docker ... 19

Hình 1.13: Kiến trúc chi tiết của Docker ... 20

Hình 2.1: Bộ lập lịch ... 22

Hình 2.2: Điều phối container và các thành phần ... 23

Hình 2.3: Cách thức thu thập log trước đây ... 26

Hình 3.1: Luồng triển khai liên tục cơ bản ... 28

Hình 3.2: Mô hình rẽ nhánh ... 30

Hình 3.3: Máy chủ CI Jenkins ... 31

Hình 3.4: Kiến trúc master-slave của Jenkins [15] ... 32

Hình 3.5: Kiến trúc của Docker Swarm [16] ... 33

Hình 3.6: Kiến trúc của Apache Mesos ... 35

Hình 3.7: Kiến trúc Mesosphes Marathon [17] ... 35

Hình 3.8: Kiến trúc của Kubernetes [10] ... 36

Hình 3.9: Ánh xạ Service và Pod trong Kubernetes ... 37

Hình 3.10: Phần mềm Slack ... 39

Hình 3.11: Luồng sử dụng cơ bản Fluentd với Elasticsearch và Kibana ... 41

Hình 3.12: Heapster trong Kubernetes [20] ... 42

Hình 3.13: Kiến trúc Prometheus [21] ... 43

Hình 3.14: Hệ thống triển khai liên tục hoàn thiện ... 44

Hình 3.15: Kết nối mạng triển khai ... 45

Hình 4.1: Mối quan hệ của ccs-service và forex-service ... 47

Hình 4.2: Mỗi vi dịch vụ có thể có nhiều bản sao chạy ... 48

Hình 4.3: Cách tổ chức mã nguồn ... 48

Hình 4.4: Cấu hình webhook cho build tiền hợp nhất trên Gitlab ... 49

Hình 4.5: Cấu hình Gitlab plugin trên Jenkins cho tiền hợp nhất ... 50

(9)

Hình 4.6 Trạng thái build tiền hợp nhất được cập nhật theo thời gian thực trên

Gitlab ... 51

Hình 4.7: Build tiền hợp nhất chạy thành công ... 51

Hình 4.8: Thông báo từ Jenkins tới Slack ... 52

Hình 4.9: Groovy DSL cho Jenkins ... 52

Hình 4.10: Các tác vụ trong Jenkins ... 53

Hình 4.11: Cách thức kết nối mạng trong kubernetes ... 54

Hình 4.12: Các máy trong Kubernetes cluster ... 55

Hình 4.13: Cách thức cài đặt và quản lý log ... 55

Hình 4.14: Cách thức cài đặt Prometheus ... 56

(10)

DANH MỤC BẢNG BIỂU

Bảng 3-1: So sánh Docker Swarm, Mesosphere Marathon và Kubernetes ... 38 Bảng 3-2: So sánh Logstash và Fluentd ... 40 Bảng 4-1: Kết quả của giải pháp triển khai liên tục ... 58

(11)

MỞ ĐẦU

Trong những thập kỉ qua, chúng ta đã chứng kiến nhiều sự thay đổi trong cách mà một tổ chức phát triển và chuyển giao phần mềm, đặc biệt là về tốc độ và chất lượng chuyển giao [1] . Trước đây, mô hình phát triển phần mềm phổ biến là mô hình thác nước, trong đó việc phát triển được chia làm nhiều giai đoạn từ việc lập kế hoạch, phân tích yêu cầu, thiết kế hệ thống, cài đặt, kiểm thử, triển khai và bảo trì. Tuy nhiên, tỉ lệ thành công của những dự án phát triển phần mềm theo mô hình thác nước là rất thấp. Một trong những lí do phổ biến đó là yêu cầu hệ thống được khảo sát và được sử dụng để xây dựng phần mềm từ đầu dự án về cơ bản không chính xác hoặc có thiếu sót: có những yêu cầu chỉ sinh ra khi người sử dụng thực sự dùng phần mềm.

Những phương pháp xây dựng phần mềm linh hoạt (agile) được phát minh để khắc phục những điểm yếu của mô hình thác nước đó. Thay vì để người dùng phải chờ đợi 6 tháng hay 1 năm cho mỗi lần phát hành, các tổ chức sẽ liên tục cập nhật phần mềm cho người sử dụng (thường là 1 tháng), thu thập phản hồi, sửa đổi hay bổ sung thêm yêu cầu để cải tiến phần mềm cho những lần cập nhật sau.

Vấn đề phát triển phần mềm đã được cải thiện đáng kể, tuy nhiên vấn đề mới lại nảy sinh: các công việc liên quan tới vận hành cũ không còn theo kịp tốc độ phát triển phần mềm: những nhà phát triển muốn phát hành bản cập nhật mới nhanh nhất có thể để có thể lấy phản hồi từ người sử dụng, nhưng qúa trình từ các bản dịch tới khi sản phẩm được triển khai thành công mất nhiều thời gian.

Các khái niệm tích hợp, chuyển giao và triển khai liên tục được giới thiệu với những kinh nghiệm thực tiễn giúp giải quyết vấn đề nêu trên. Tuy nhiên, do giới hạn về công nghệ, mục tiêu của triển khai liên tục chưa đạt được vào thời điểm mà nó được giới thiệu: triển khai đòi hỏi phần cứng, mà việc chuẩn bị phần cứng mất nhiều thời gian (mua bán, cài đặt, quản lý, ...).

Với sự phát triển của Internet và sự xuất hiện của tính toán đám mây, các ứng dụng không còn bị bó buộc vào cơ sở hạ tầng vật lý mà đã có thể được triển khai trên các nền tảng đám mây. Những ứng dụng có thể sử dụng tài nguyên co dãn của đám mây để mở rộng, thu hẹp tùy vào nhu cầu sử dụng. Những ứng dụng như vậy được gọi là những ứng dụng dựa vào đám mây.

Kiến trúc các hệ thống phần mềm cũng tiến hóa để sử dụng lợi ích mà nền tảng đám mây mang lại. Trước đây, những dụng máy chủ (server-side application) truyền thống thường được xây dựng bằng một kiến trúc gồm nhiều lớp, với mỗi lớp chứa các loại thành phần khác nhau.

(12)

Lớp trên cùng, chịu trách nhiệm giao tiếp với người dùng, là lớp giao diện. Lớp giao diện thực hiện việc xử lý các yêu cầu HTTP và trả lại kết quả là giao diện HTML hoặc dữ liệu ở dạng JSON/XML tới người sử dụng.

Ngay phía dưới lớp giao diện là lớp logic nghiệp vụ, chịu trách nhiệm tính toán và xử lý dữ liệu thô sang dữ liệu có ý nghĩa theo nghiệp vụ nhất định. Lớp logic nghiệp vụ không tương tác với cơ sở dữ liệu một cách trực tiếp mà dựa vào lớp truy xuất dữ liệu phía dưới.

Cuối cùng là lớp truy xuất dữ liệu. Đây là cửa ngõ để truy cập vào cơ sở dữ liệu của các lớp khác. Lớp truy xuất dữ liệu cung cấp giao diện (API) một khối cho các lớp khác, độc lập với cơ sở dữ liệu đang được sử dụng (MySQL, PostgresSQL, …)

Những ứng dụng sử dụng kiến trúc này thường được đóng gói và triển khai như một khối thống nhất. Những ứng dụng như vậy gọi là ứng dụng một khối (monolith).

Ứng dụng một khối có ưu điểm là dễ phát triển, kiểm thử và triển khai; tuy nhiên do tất cả các thành phần (module) đều được đóng vào một gói, ứng dụng ngày càng trở nên lớn và phức tạp, khiến việc hiểu và sửa đổi ứng dụng khó khăn hơn. Kích cỡ của ứng dụng sẽ làm chậm quá trình khởi động. Mỗi khi có cập nhật gì thì toàn bộ ứng dụng cần phải được triển khai lại, dẫn đến việc triển khai liên tục trở nên khó khăn hơn. Việc scale ứng dụng cũng sẽ đòi hỏi nhiều tài nguyên và phức tạp. Ngoài ra, lỗi trong một module hoàn toàn có thể khiến cho cả ứng dụng một khối bị sập. Khi muốn thay đổi công nghệ mới thì có khi cả ứng dụng cần phải được phát triển lại, gây lãng phí thời gian và tiền bạc.

Kiến trúc vi dịch vụ (microservice) được sinh ra để giải quyết những vấn đề trên.

Ý tưởng của kiến trúc này là chia ứng dụng ra những dịch vụ nhỏ hơn, hoàn toàn riêng biệt với nhau và giao tiếp với nhau thông qua các API. Ví dụ: những dịch vụ liên quan tới nghiệp vụ được phát triển riêng, cung cấp các API cho các dịch vụ khác. Những thành phần giao diện người dùng cũng được tách ra như một dịch vụ, chúng giao tiếp với những dịch vụ nghiệp vụ để lấy dữ liệu cần thiết và hiển thị lên cho người dùng.

Kiến trúc vi dịch vụ giải quyết được những vấn đề mà những ứng dụng một khối gặp phải. Đầu tiên, vviệc chia ứng dụng ra thành những dịch vụ nhỏ hơn cho phép các dịch vụ được phát triển và kiểm thử nhanh chóng, độc lập. Mỗi đội sẽ được giao phát triển một hoặc một vài dịch vụ trong ứng dụng, cách biệt với các dịch vụ khác. Điều này khiến mã nguồn trở nên nhỏ hơn, dễ hiểu và quản lý. Ngoài ra, do tính chất độc lập, mỗi dịch vụ nhỏ trong ứng dụng có thể được triển khai độc lập bởi mỗi đội. Do các dịch vụ trong ứng dụng chỉ giao tiếp với nhau thông qua API, mỗi dịch vụ có thể sử dụng công nghệ riêng. Điều này giúp việc cập nhật công nghệ cho toàn bộ ứng dụng trở nên dễ dàng (cập nhật lần lượt). Nhờ có kiến trúc vi dịch vụ, việc tích hợp

(13)

Không những thế, việc mmở rộng (scale) ứng dụng trở nên đơn giản và nhanh chóng, do việc mở rộng ứng dụng sẽ được phân nhỏ thành mở rộng các dịch vụ.

Kiến trúc vi dịch vụ hiện nay thường được sử dụng cùng với công nghệ container. Mỗi ảnh container là một đóng gói của ứng dụng kèm những thư viện cần thiết để ứng dụng có thể chạy được. Container sử dụng nhân chung với nhân hệ điều hành nên nhẹ hơn nhiều so với công nghệ máy ảo. Ngoài ra, container giúp cho ứng dụng chạy như nhau trên mọi môi trường, do vậy hỗ trợ tốt trong việc triển khai các dịch vụ trong kiến trúc vi dịch vụ. Cùng với nền tảng đám mây, kiến trúc vi dịch vụ và công nghệ container giúp cho ý tưởng về việc triển khai liên tục trở nên ngày một thực tế hơn.

Tuy nhiên, vấn đề gặp phải của kiến trúc vi dịch vụ sử dụng container là khi số lượng dịch vụ tăng lên, việc quản lý và phối hợp những dịch vụ đó trở nên khó hơn nhiều lần so với các ứng dụng một khối. Ngoài ra, việc giám sát nhiều dịch vụ cũng phức tạp hơn so với cách triển khai truyền thống; khi có lỗi xảy ra thì việc xem log và sửa lỗi cũng gây những khó khăn nhất định cho đội phát triển.

Với thực trạng như vậy, luận văn sẽ đề xuất ra giải pháp để giải quyết những vấn đề trên, từ đó đảm bảo được việc tích hợp, triển khai liên tục cho quá trình phát triển phần mềm.

Luận văn bao gồm 04 chương với nội dung của các chương được phân bố như sau:

Chương 1 sẽ giới thiệu về các khái niệm cơ bản liên quan tới tính toán đám mây, tích hợp và triển khai liên tục, các kiến trúc hệ thống phần mềm cũng như công nghệ container.

Chương 2 tập trung vào việc phân tích yêu cầu để xây dựng mô hình triển khai liên tục cho cho một hệ thống vi dịch vụ sử dụng container.

Dựa vào yêu cầu đã được phân tích ở Chương 2, Chương 3 đưa ra đề xuất thiết kế một luồng triển khai liên tục cho các hệ thống dựa trên vi dịch vụ nói chung, đồng thời trình bày và so sánh các công nghệ hiện tại cho các thành phần trong luồng để xây dựng nên một thiết kế hoàn thiện.

Trong Chương 4, luận văn trình bày cụ thể cách thức cài đặt một luồng triển khai liên tục mẫu cho hệ thống phần mềm chuyển đổi tiền tệ và đánh giá kết quả đạt được.

Phần Kết luận sẽ tổng kết thành quả nghiên cứu của luận văn và hướng phát triển dự định trong tương lai.

(14)

CHƯƠNG 1: KIẾN THỨC CƠ BẢN

Cùng với sự xuất hiện và phổ biến của phương pháp phát triển phần mềm linh hoạt, các ý tưởng mới liên tục xuất hiện để tận dụng tối đa lợi ích mà phương pháp này mang lại. Trong đó, nổi bật nhất là ý tưởng về việc tích hợp, chuyển giao và triển khai liên tục: phần mềm sẽ được dịch (build), đóng gói và phát hành ngay khi có sự thay đổi trên hệ thống quản lý mã. Tuy nhiên, ý tưởng này không thể thực hiện được tại thời điểm mà nó được đề xuất do nhiều giới hạn về công nghệ và cơ sở hạ tầng. Với sự xuất hiện của tính toán đám mây, sự tiến hóa trong kiến trúc phần mềm (từ kiến trúc một khối tới kiến trúc vi dịch vụ) hay ý tưởng về đóng gói ứng dụng trong container, việc xây dựng một hệ thống triển khai liên tục đã trở nên khả thi hơn. Để giúp làm rõ hơn những nội dung trong các chương tiếp theo, chương này sẽ giới thiệu các khái niệm cơ bản nêu trên một cách chi tiết.

1.1 Tính toán đám mây

1.1.1 Giới thiệu về tính toán đám mây

Tính toán đám mây là sự cung cấp, phân phối sức mạnh tính toán, hệ thống lưu trữ, ứng dụng hoặc các nguồn tài nguyên công nghệ thông tin khác thông qua nền tảng đám mây, sử dụng kênh truyền internet và giá cả được tính toán dựa vào khối lượng sử dụng [2].

Sử dụng tính toán đám mây, một công ty hay tổ chức không cần đầu tư nhiều chi phí ban đầu vào việc chuẩn bị các thiết bị phần cứng, hay dành nhiều thời gian để quản lý chúng. Thay vào đó, công ty/tổ chức chỉ cần cung cấp đúng yêu cầu về chủng loại và kích thước nguồn tài nguyên tính toán cho nhà cung cấp dịch vụ, mọi thứ sẽ được cung ứng gần như ngay lập tức.

Một đặc điểm quan trọng của đám mây đó là các dịch vụ gần như trong suốt với người dùng, nghĩa là người dùng gần như không cần quan tâm làm thế nào mà dịch vụ đó được cung ứng mà chỉ cần tập trung vào việc làm thế nào để sử dụng chúng. Với giao diện người dùng đơn giản, hầu hết các dịch vụ đám mây đòi hỏi rất ít kiến thức về quản trị.

Tính toán đám mây được chia thành ba mô hình cơ bản [3]:

Cơ sở hạ tầng như một dịch vụ (Infrastructure as a service - IaaS): cung cấp cho người dùng các tài nguyên tính toán ở cấp độ thấp nhất, bao gồm: máy chủ, mạng, hệ thống lưu trữ, trung tâm dữ liệu, ... và giá cả tính theo khối lượng sử dụng. Đối với người sử dụng, đặc biệt là các doanh nghiệp, lợi ích mà IaaS mang lại là rất lớn, điển hình là việc không cần đầu tư phần cứng, cơ sở hạ tầng

(15)

có thể thay đổi linh động tùy vào nhu cầu sử dụng và việc có nhiều dịch vụ linh hoạt, sáng tạo đi kèm.

Nền tảng như một dịch vụ (Platform as a service - PaaS): cung cấp môi trường được xây dựng trên nền tảng đám mây với tất cả mọi thứ cần thiết để phát triển và chuyển giao những ứng dụng trên nền web (cloud). Người dùng không cần gánh chi phí cũng như quan tâm tới các công việc phức tạp liên quan tới việc mua, quản lý thành phần phần cứng, phần mềm, cung ứng hay hosting như cách truyền thống. Lợi ích của PaaS đối với người dùng trước hết là ở việc phát triển và đưa phần mềm ra thị trường nhanh hơn so với trước đây, việc triển khai phần mềm mới lên đám mây chỉ mất vài phút. Ngoài ra, Paas giúp giảm thiểu sự phức tạp của việc quản lý phần giữa (middleware).

Phần mềm như một dịch vụ(Software as a service - SaaS): là các ứng dụng trên nền tảng đám mây, chạy trên những máy tính "nằm trong đám mây", được sở hữu và vận hành bởi nhà cung cấp nền tảng đám mây, kết nối tới người dùng qua internet và trình duyệt. Với SaaS, người dùng có thể nhanh chóng đăng kí và bắt đầu sử dụng phần mềm mà gần như không phải làm bất cứ việc gì liên quan tới phát triển; các ứng dụng và dữ liệu có thể được truy cập từ bất cứ máy tính nào có kết nối Internet. Người dùng cũng không cần lo lắng về việc mất mát dữ liệu do dữ liệu đã được lưu trữ trong đám mây. Hơn thế, các dịch vụ có khả năng scale linh hoạt theo nhu cầu sử dụng, do vậy hiệu năng luôn được đảm bảo.

1.1.2 Sự phổ biến của ứng dụng dựa vào đám mây

Việc chuyển đổi sang đám mây là sự phát triển tự nhiên đối với việc cung ứng các dịch vụ công nghệ thông tin. Nền tảng đám mây cung cấp một môi trường với các tài nguyên đa dạng, từ tính toán, lưu trữ cho tới mạng, có khả năng co dãn, linh động theo nhu cầu sử dụng. Ngày càng nhiều công ty, tổ chức chuyển dần sang phát triển phần mềm, ứng dụng cho nền tảng đám mây thay vì cách phát triển truyền thống, bởi:

Tốc độ: Ngày nay tốc độ có yếu tố quan trọng quyết định sự tồn tại của một công ty, tổ chức. Các tính năng mới khi được hoàn thành cần được triển khai ngay để thu hút người sử dụng, giành lấy thị phần. Những công ty lớn như Google, Facebook, Amazon, Uber, Grab, ... triển khai tính năng mới, hay đơn giản chỉ là bản vá, bản nâng cấp hàng chục tới hàng trăm lần mỗi ngày. Điều này giúp họ thu hút người dùng trước khi đối thủ kịp phản ứng, nhanh chóng sửa lỗi trước khi có vấn đề phát sinh. Đặc điểm co dãn và khả năng kết nối của đám mây giúp việc triển khai liên tục này trở nên khả thi.

(16)

Khả năng cô lập lỗi: Kiến trúc sử dụng cho các ứng dụng dựa vào đám mây giúp cho việc cô lập lỗi trở nên dễ dàng hơn. Đối với các phần mềm truyền thống, kiến thúc thường được sử dụng là một khối, tuy nhiên đối với nền tảng đám mây, kiến trúc phổ biến nhất hiện nay là vi dịch vụ. Với vi dịch vụ, khi lỗi xảy ra, chỉ những thành phần có lỗi bị ảnh hưởng. Chúng có thể được tắt đi và thay thế mà không gây ảnh hưởng tới cả hệ thống tổng thể. Cụ thể về kiến trúc này sẽ được giới thiệu trong các phần sau.

Khả năng co dãn (scale): Khi ứng dụng giành được thị phần nhất định, số lượng người dùng có thể sẽ tăng lên nhanh chóng. Trước khi xuất hiện nền tảng đám mây, các công ty thường phải nâng cấp phần cứng cho máy chủ bằng việc nâng cao sức mạnh máy (scale-up), do việc mở rộng năng lực theo chiều ngang (scale-out) đòi hỏi quá trình mua máy, cài đặt, tích hợp mất quá nhiều thời gian và phần mềm truyền thống không được thiết kế phù hợp cho việc scale-out. Kể cả khi việc scale-out có thể được thực hiện thì cũng không hiệu quả. Với sự xuất hiện của những nền tảng đám mây như Amazon Web Services (AWS), Google Cloud Platform (GCP) hay Microsoft Azure, cùng với việc xuất hiện các công nghệ, kiến trúc mới cho nền tảng đám mây, việc mở rộng theo chiều ngang (scale-out) có thể được thực hiện chỉ trong vòng vài phút.

1.2 Tích hợp, chuyển giao và triển khai liên tục

1.2.1 Tích hợp liên tục

Tích hợp liên tục là quá trình tự động hóa việc dịch (build) và kiểm thử mã mỗi khi các thành viên trong đội cập nhật mã lên hệ thống quản lý phiên bản (tích hợp liên tục đòi hỏi những nhà phát triển phải tích hợp mã vào một kho chứa mã duy nhất).

Tích hợp liên tục khuyến khích các nhà phát triển chia sẻ mã và các bài kiểm thử đơn vị (unit test) bằng việc hợp nhất những thay đổi trên máy lên kho quản lý mã chung ngay khi hoàn thiện một tác vụ nhỏ nào [4]. Từ yêu cầu hợp nhất, các máy chủ sẽ kích hoạt luồng (pipeline): lấy mã mới về máy chủ CI, chạy quá trình dịch, kiểm thử, … Nếu có lỗi xảy ra ở bất cứ phần nào trong luồng, sửa lỗi là việc được ưu tiên hàng đầu.

Tích hợp liên tục ngày càng trở nên phổ biến hơn bởi những nhà phát triển phần mềm thường sẽ làm việc một cách độc lập, và cuối cùng họ sẽ cần tích hợp mã với những thành viên khác trong đội, hoặc rộng hơn là các đội khác trong công ty. Việc chờ đợi nhiều ngày để tích hợp mã sẽ gây ra nhiều lỗi hợp nhất (merge conflict) khó giải quyết. Luồng (pipeline) tích hợp được khởi động mỗi khi có mã được đẩy lên kho chứa mã chung giúp giảm thiểu đáng kể vấn đề trên.

(17)

Với mỗi công ty, tổ chức, pipeline tích hợp được xác định tùy thuộc vào công cụ sử dụng, ngôn ngữ lập trình cũng như rất nhiều yếu tố khác, tuy nhiên luồng thực hiên cơ bản bao gồm các bước sau [5]:

1. Đẩy mã lên kho chứa mã chung 2. Phân tích tĩnh

3. Kiểm thử trước khi triển khai

4. Đóng gói và triển khai lên môi trường kiểm thử 5. Kiểm thử sau khi triển khai

1.2.2 Chuyển giao liên tục

Về cơ bản, một luồng chuyển giao liên tục bao gồm các bước giống như luồng tích hợp liên tục đã liệt kê ở phần trước đó. Điểm khác biệt lớn nhất đó là: bước "5.

Kiểm thử sau khi triển khai" trong tích hợp liên tục thường đòi hỏi việc can thiệp bằng tay. Các bản dịch không vượt qua được các bài kiểm tra ở bước này sẽ bị loại. Còn trong Chuyển giao liên tục, sẽ có các cơ chế để tự động hóa bước này. Kết quả cuối cùng là một bản dịch mà luôn sẵn sàng để triển khai trên môi trường sản phẩm thực tế.

Hình 1.1: Các bước cơ bản trong tích hợp liên tục [5]

(18)

1.2.3 Triển khai liên tục

Triển khai liên tục là mục tiêu cuối cùng trong chuỗi tự động hóa này. Bản dịch cuối cùng sau bước chuyển giao liên tục là bản dịch luôn sẵn sàng để triển khai vào môi trường thực tế, tuy nhiên việc triển khai hay không và chọn phiên bản nào để triển khai lại phụ thuộc vào quyết định của đội vận hành. Trong triển khai liên tục, bất cứ bản dịch nào vượt qua được tất cả các bài kiểm thử đều sẽ được triển khai tự động lên môi trường sản phẩm thực tế. Không có sự can thiệp của con người trong qúa trình này.

1.3 Kiến trúc hệ thống

Trong những năm gần đây, kiến trúc phần mềm web đã phát triển với một tốc độ nhanh chóng. Với sự phổ biến của các dịch vụ Internet, chúng ta có thể thấy sự chuyển dịch từ kiến trúc một khối theo tầng/lớp, sang kiến trúc hướng dịch vụ và như hiện nay là kiến trúc vi dịch vụ. Việc lựa chọn một kiến trúc phần mềm cụ thể phụ thuộc hoàn toàn vào những yêu cầu về khả năng co dãn (scale), độ phức tạp hay khả năng triển khai. Đối với ứng dụng web, khả năng co dãn là một trong những yếu tố quan trọng hàng đầu.

Hình 1.2 thể hiện sự so sánh của ba kiểu kiến trúc nêu trên về khả năng co dãn (scale) và sự tách biệt của các thành phần trong hệ thống.

Hình 1.2: Bảng so sánh kiến trúc một khối, kiến trúc hướng dịch vụ và kiến trúc vi

(19)

1.3.1 Kiến trúc một khối

Kiến trúc một khối thường sẽ gộp những tính năng thiết yếu lại, từ đó phát triển cũng như triển khai như một khối duy nhất. Trong kiến trúc một khối, cách thiết kế phổ biến là phân chia các thành phần theo dạng module hoặc theo lớp. Ví dụ: phân chia thành lớp giao diện người dùng, tới lớp logic nghiệp vụ, lớp truy cập cơ sở dữ liệu và cuối cùng là lớp tích hợp để tích hợp với các dịch vụ ngoài.

Hình 1.3: Kiến trúc một khối cho ứng dụng đặt hàng Ưu điểm của kiến trúc này bao gồm:

Đơn giản hóa cho việc phát triển và kiểm thử: do các thành phần đều được đóng gói vào làm một, việc phát triển và kiểm thử chỉ cần thực hiện trên một khối.

Đơn giản cho việc triển khai: khi máy chủ đã được cài đặt các phần mềm thiết yếu, cách triển khai đơn giản nhất là chỉ cần sao chép phần mềm đã đóng gói vào máy chủ và chạy.

Đơn giản trong việc scale theo chiều ngang: phân chia dữ liệu ra thành các thành phần khác nhau, sao chép ứng dụng ra thành nhiều phần, mỗi phần truy cập vào một phần dữ liệu, đặt tất cả các thành phần đằng sau một bộ Load Balancer.

Kiến trúc này về cơ bản vẫn hoạt động tốt đối với những giai đoạn đầu của dự án.

Nhiều hệ thống phần mềm lớn hiện nay vẫn đang sử dụng kiến trúc này. Tuy nhiên, kiến trúc một khối có nhiều điểm hạn chế như [7]: cách tiếp cận này có giới hạn về

(20)

kích thước và độ phức tạp, ứng dụng có thể trở nên quá lớn, phức tạp để có thể hiểu và tiếp tục phát triển hay kích cỡ của ứng dụng làm việc khởi động trở nên chậm hơn.

Ngoài ra, mỗi khi có cập nhật gì thì đều cần triển khai lại toàn bộ ứng dụng, do vậy việc triển khai liên tục trở nên khó khan. Nếu việc phân chia dữ liệu khó khăn, ứng dụng khó có thể scale theo chiều ngang như miêu tả ở trên. Ngoài ra, ứng dụng một khối có nhiều rào cản trong việc áp dụng các công nghệ mới, bởi việc thay đổi trong bộ khung hay ngôn ngữ lập trình có thể ảnh hưởng tới toàn bộ ứng dụng.

1.3.2 Kiến trúc hướng dịch vụ

Kiến trúc hướng dịch vụ (Service-Oriented Architecture) nổi lên như một cách để giải quyết vấn đề các thành phần phụ thuộc vào nhau quá nhiều trong kiến trúc một khối.

Kiến trúc hướng dịch vụ là mẫu kiến trúc phần mềm trong đó các thành phần ứng dụng cung cấp dịch vụ cho các thành phần khác thông qua giao thức giao tiếp qua mạng [8]. Có hai vai trò chính trong kiến trúc hướng dịch vụ: vai trò thành phần cung cấp dịch vụvai trò thành phần tiêu thụ dịch vụ. Một phần mềm có thể đóng cả hai trò, tùy vào từng hoàn cảnh cụ thể. Lớp tiêu thụ là điểm mà những thành phần tiêu thụ (có thể là người dùng, dịch vụ khác hoặc các bên thứ ba) tương tác với kiến trúc hướng dịch vụ, và Lớp cung cấp là lớp chứa tất cả các dịch vụ được định nghĩa trong kiến trúc hướng dịch vụ.

Đường giao tiếp dịch vụ doanh nghiệp (Enterprise Service Bus-ESB) là một kiểu kiến trúc tích hợp cho phép giao tiếp được thực hiện thông qua một bus chứa nhiều kết nối điểm-tới-điểm (point-to-point) giữa thành phần cung cấp và tiêu thụ.

Hình 1.4 đưa ra một ví dụ về kiến trúc hướng dịch vụ sử dụng trong hệ thống đặt hàng.

(21)

Hình 1.4: Kiến trúc hướng dịch vụ cho ứng dụng đặt hàng 1.3.3 Kiến trúc vi dịch vụ

Kiến trúc vi dịch vụ là mẫu kiến trúc phần mềm trong đó các ứng dụng phức tạp được chia nhỏ ra thành các dịch vụ nhỏ hơn, độc lập và giao tiếp với nhau thông qua những API độc lập với ngôn ngữ lập trình. Mỗi một vi dịch vụ là một ứng dụng nhỏ có kiến trúc riêng, có thể chứa logic nghiệp vụ và nhiều loại thành phần khác. Một số vi dịch vụ cung cấp API ở dạng Rest API, dạng tin nhắn (message) hoặc RPC và hầu hết các vi dịch vụ sẽ dùng API được cung cấp bởi các vi dịch vụ khác [7].

Kiến trúc vi dịch vụ có ảnh hưởng lớn trong mối quan hệ giữa ứng dụng và cơ sở dữ liệu. Thay vì dùng chung một bảng dữ liệu với các dịch vụ khác, mỗi vi dịch vụ sẽ có bảng dữ liệu riêng. Việc này có thể sẽ gây ra sự dư thừa dữ liệu do một số dữ liệu sẽ cần dùng chung bởi nhiều vi dịch vụ. Tuy nhiên, việc này là cần thiết để tránh sự phụ thuộc vào nhau. Hơn thế, mỗi một vi dịch vụ có thể có cơ sở dữ liệu riêng, với công nghệ khác với các vi dịch vụ khác, phù hợp với nhu cầu sử dụng của nó. Ví dụ:

một vi dịch vụ sử dụng MongoDB trong khi các vi dịch vụ khác sử dụng MySQL.

Một điều quan trọng trong kiến trúc này đó là mỗi một vi dịch vụ phải là một thành phần có thể chạy và triển khai độc lập được, việc tắt một vi dịch vụ không thể gây ra hậu quả lớn tới toàn bộ vi dịch vụ khác. Kiến trúc vi dịch vụ có thể được xem như là một phiên bản con của kiến trúc hướng dịch vụ, trong đó quy mô của mỗi dịch vụ nhỏ hơn, có cơ sở dữ liệu riêng và giao tiếp qua các dạng API chứ không thông qua bus. Hình 1.5 là thể hiện một ví dụ về kiến trúc vi dịch vụ cho ứng dụng đặt hàng trực tuyến:

(22)

Hình 1.5: Kiến trúc vi dịch vụ cho ứng dụng đặt hàng

Kiến trúc vi dịch vụ có nhiều ưu điểm, giúp xử lý các vấn đề mà kiến trúc một khối gặp phải như:

Kiến trúc vi dịch vụ giúp giải quyết được vấn đề ứng dụng phức tạp bằng cách chia nhỏ thành các dịch vụ nhỏ, dễ quản lý hơn (vi dịch vụ). Mỗi một vi dịch vụ sẽ được phát triển nhanh hơn, dễ hiểu và bảo trì.

Mỗi một vi dịch vụ từ nay có thể được phát triển độc lập bởi một đội, miễn là đảm bảo API giao tiếp.

Kiến trúc này giúp cho việc cập nhật công nghệ dễ dàng do mỗi vi dịch vụ có thể sử dụng công nghệ hoàn toàn riêng biệt.

Ngoài ra, mỗi một vi dịch vụ có thể được triển khai một cách độc lập, do vậy giúp cho việc triển khai liên tục trở nên khả thi.

Việc scale ứng dụng giờ được chuyển thành scale từng vi dịch vụ độc lập, giúp tiết kiệm tài nguyên, scale nhanh hơn, có thể scale-out do mỗi vi dịch vụ có bảng cơ sở dữ liệu riêng.

Tuy nhiên, kiến trúc vi dịch vụ có những hạn chế nhất định như:

Kiến trúc vi dịch vụ làm tăng sự phức tạp của dự án, do một ứng dụng phải được chia nhỏ ra với các API giao tiếp giữa các ứng dụng phải được định nghĩa cụ thể và rõ ràng.

(23)

Việc áp dụng một vài thay đổi liên quan tới nhiều dịch vụ đòi hỏi việc triển khai cẩn thận, có cơ chế cập nhật từ từ (roll-out) ở từng dịch vụ.

Triển khai ứng dụng vi dịch vụ là rất phức tạp: một ứng dụng có thể chứa hàng chục vi dịch vụ, mỗi một vi dịch vụ có thể chạy nhiều bản sao. Cần có cách thức đóng gói để triển khai mỗi dịch vụ nhanh chóng. Cách thức kết nối giữa các vi dịch vụ cần được cấu hình cẩn thận để đảm bảo giao tiếp. Cần có cơ chế tự động hóa quá trình này, nếu không việc scale sẽ đòi hỏi rất nhiều nguồn lực, làm giảm giá trị mà kiến trúc vi dịch vụ đang hướng tới.

1.4 Các mô hình triển khai

Có nhiều mô hình triển khai trong thực tế tùy thuộc vào kiến trúc phần mềm, cơ sở hạ tầng có sẵn và chiến lược của từng công ty. Tuy nhiên, chương này sẽ chỉ liệt kê 3 mô hình triển khai cơ bản để phân biệt giữa ứng dụng một khối và vi dịch vụ, cách đóng gói các bản build sử dụng để triển khai và phương án triển khai có tùy biến hay không [5].

1.4.1 Mô hình triển khai tùy biến

Ngày nay, cách phổ biến nhất để build và triển khai ứng dụng vẫn là sử dụng mô hình triển khai tùy biến. Chúng ta dựng lên một máy chủ web với ứng dụng cần chạy và cập nhật ứng dụng mỗi khi có bản phát hành mới. Sự thay đổi có thể xảy ra trong cấu hình, bản build (các tệp JAR, WAR, ...) hay cơ sở dữ liệu trên máy chủ đó, miễn là ứng dụng hoạt động.

Với mô hình triển khai tùy biến, ta không thể biết chính xác rằng cấu hình môi trường phát triển, kiểm thử và môi trường sản phẩm (production) có giống nhau hay không. Thậm chí cấu hình các máy chủ khác nhau trong cùng môi trường sản phẩm cũng có thể khác nhau. Ngoài ra, khó có thể đảm bảo được tất cả các máy đều được cập nhật đúng một phiên bản. Mỗi máy chủ chứa tất cả mọi thứ mà ứng dụng cần chạy và ứng dụng thì lớn dần theo thời gian. Sau một thời gian triển khai, không một ai nắm chắc về cấu hình hiện sử dụng vì cấu hình được thêm vào, sửa đổi từng ngày.

Mô hình triển khai này dù ban đầu khá đơn giản nhưng nó sẽ dần kết nối mọi thứ vào nhau, tăng độ phức tạp theo thời gian và tạo ra sự không nhất quán. Khi có bản phát hành mới, việc cập nhật lại máy chủ có thể tạo ra thời gian ngừng hoạt động. Với mô hình này thì triển khai liên tục hoàn toàn không khả thi, và điều này sẽ dẫn tới hậu quả khác: do không triển khai thường xuyên, càng lúc càng có nhiều sự khác nhau giữa bản đang hoạt động và bản phát hành, tăng thêm khả năng cập nhật thất bại. Để

(24)

giải quyết vấn đề này, triển khai nên được thực hiện theo mô hình không tùy biến:

triển khai gồm những đóng gói ứng dụng độc lập, đủ yêu cầu hoạt động.

1.4.2 Mô hình không tùy biến kết hợp với Reverse Proxy

Việc chuyển đổi mô hình triển khai sang mô hình không tùy biến sẽ giải quyết được vấn đề khác nhau nêu trên. Khi triển khai, thay vì sử dụng các bản build đơn thuần của ứng dụng, ta sử dụng các bản đóng gói máy ảo hoặc container chứa tất cả môi trường cần thiết để ứng dụng hoạt động. Cách làm này đảm bảo được tính đồng nhất giữa môi trường build, kiểm thử và môi trường sản phẩm.

Khi triển khai, để đảm bảo không có thời gian ngừng hoạt động, một reverse proxy có thể được sử dụng: tất cả kết nối tới máy chủ chạy ứng dụng đều thông qua reverse proxy; khi cần cập nhật ứng dụng, ta triển khai hoàn toàn bản phát hành mới trên một máy chủ khác, đảm bảo ứng dụng chạy tốt trên đó và cấu hình reverse proxy để trỏ vào máy chủ vừa triển khai.

Hình 1.6: Mô hình triển khai không tùy biến - cập nhật ứng dụng [5]

(25)

Hình 1.7: Mô hình triển khai không tùy biến - cấu hình reverse proxy khi cập nhật [5]

1.4.3 Mô hình không tùy biến với ứng dụng vi dịch vụ

Trong mô hình triển khai không tùy biến, mỗi một bản đóng gói bao gồm toàn bộ ứng dụng, khiến cho việc kiểm thử, triển khai mất nhiều thời gian. Điều này phần nào hạn chế việc triển khai thường xuyên. Áp dụng mô hình không tùy biến với ứng dụng sử dụng kiến trúc vi dịch vụ giúp đơn giản hóa được quá trình này: mỗi bản đóng gói sẽ chỉ gồm một hoặc một vài dịch vụ, các bản đóng gói của các dịch vụ khác nhau có thể được triển khai trên các máy khác nhau, giao tiếp giữa các dịch vụ được thực hiện qua mạng.

Điểm khác biệt cơ bản giữa mô hình này với mô hình không tùy biến ở trên là:

do kích cỡ của các dịch vụ khá nhỏ, không phải lúc nào triển khai cũng cần thực hiện trên một máy chủ mới. Dịch vụ mới hoàn toàn có thể được triển khai trên máy đang chạy, cấu hình reverse proxy sẽ trỏ trực tiếp vào dịch vụ thay vì vào máy chủ.

(26)

Hình 1.8: Mô hình triển khai không tùy biến với vi dịch vụ - cập nhật dịch vụ [5]

Hình 1.9: Mô hình triển khai không tùy biến với vi dịch vụ - cấu hình reverse proxy [5]

(27)

1.5 Khái niệm Container

Container là phương pháp ảo hoá ở mức hệ điều hành, cho phép chạy một ứng dụng cùng các thư viện nó phụ thuộc trong các tiến trình có tài nguyên được cách li.

Container giúp đóng gói mã, công cụ hệ thống, các cấu hình ... của ứng dụng vào trong một khối duy nhất gọi là ảnh container [9].

Công nghệ container có trên hầu hết các hệ điều hành, từ Windows, Linux, Mac, do vậy các phần mềm được container hóa luôn chạy như nhau trên tất cả các môi trường. Container giúp đảm bảo ứng dụng có thể được triển khai nhanh chóng, độ tin cậy cao và nhất quán, phù hợp với mô hình triển khai không tùy biến như đã đề cập ở phần trước.

Hình 1.10: Công nghệ container

Công nghệ container và công nghệ máy ảo có nhiều điểm tương đồng, ví dụ như về lợi ích liên quan tới phân phối và cách li tài nguyên. Tuy nhiên, container là ảo hoá ở mức hệ điều hành còn máy ảo là công nghệ ảo hoá phần cứng. Container có tính di động cao và sử dụng tài nguyên hiệu quả hơn. Sự khác nhau về mặt kiến trúc của container và máy ảo truyền thống được thể hiện rõ hơn trong Hình 1.11 dưới đây:

(28)

Hình 1.11: Khác biệt giữa container và máy ảo

Container là một lớp trừu tượng nằm ở tầng ứng dụng, đóng gói mã và các lệ thuộc vào cùng nhau. Nhiều container có thể được chạy trên cùng một máy và chia sẻ nhân hệ điều hành với các container khác. Mỗi container sẽ chạy như những tiến trình được cách li trong user space (Trong Linux, để đảm bảo tính cách li, container thường sử dụng namespace và control group). Các container có kích thước nhẹ hơn, chiếm ít không gian bộ nhớ hơn các máy ảo, do vậy có khả năng khởi động gần như ngay tức thời.

Máy ảo là một lớp trừu tượng của phần cứng vật lý, có khả năng biến một máy chủ thành nhiều máy chủ con. Tầng hypervisor cho phép nhiều máy ảo chạy trong cùng một máy thật. Mỗi một máy ảo gồm đầy đủ hệ điều hành, các ứng dụng đi kèm, các thư viện cơ bản, do vậy thường chiếm tới hàng chục GB bộ nhớ. Các máy ảo thường mất nhiều thời gian để khởi động.

Công nghệ container đã xuất hiện từ lâu, tuy nhiên nó ít khi được sử dụng do sự phức tạp trong quá trình tạo ra một container ổn định và việc đảm bảo môi trường thực thi. Tuy nhiên, với sự xuất hiện của docker, container trở nên ngày càng phổ biến.

Docker đóng vai trò như một lớp trung gian giúp ẩn đi môi trường chạy phức tạp của container với người dùng.

Phần lõi của Docker là Docker Engine, một ứng dụng khách-chủ với các thành phần như sau (Hình 1.12: Kiến trúc Docker) [10]:

• Một tiến trình daemon (chạy thông qua lệnh dockerd) đóng vai trò là server

• Các RestAPI xác định giao diện mà các chương trình khác dùng để tương tác với daemon và hướng dẫn nhiệm vụ cần làm

• Một ứng dụng CLI đóng vai trò là client (chạy thông qua lệnh docker)

(29)

Hình 1.12: Kiến trúc Docker

Docker daemon (dockerd) lắng nghe các yêu cầu docker API và quản lý các đối tượng Docker như ảnh, container, mạng và ổ chứa (volume). Một daemon có thể giao tiếp với các daemon khác để quản lý các dịch vụ docker.

Docker client (docker) là cách cơ bản mà nhiều người dùng sử dụng để tương tác với docker. Khi sử dụng các câu lệnh như docker run, máy trạm gửi những câu lệnh này tới dockerd, nơi thực sự thực thi nhiệm vụ. Docker client có thể giao tiếp với nhiều docker daemon.

Docker registry là nơi lưu trữ các ảnh Docker. Các registry nổi tiếng như Docker Hub hay Docker Cloud là các registry công khai mà bất cứ ai cũng có thể sử dụng, và mặc định thì chương trình Docker cũng được cấu hình để tìm kiếm ảnh trong Docker Hub. Ngoải ra, người dùng cũng có thể tự chạy registry của riêng mình. Khi câu lệnh docker pull hay docker run được gọi, các ảnh container tương ứng sẽ được tải về từ registry. Ngược lại, câu lệnh docker push cho phép người dùng đẩy ảnh lên registry đó.

Trong Docker phân biệt hai khái niệm ảnh và container. Ảnh là một bản mẫu với các câu lệnh để hướng dẫn tạo ra Docker container. Một ảnh thường được xây dựng lên dựa vào các ảnh khác. Ví dụ: người dùng có thể tạo một ảnh dựa vào ảnh ubuntu,

(30)

sau đó cài đặt thêm ứng dụng apache server, chỉnh sửa cấu hình cần thiết và đóng gói lại thành một ảnh mới. Để tạo ảnh thì Docker sử dụng Dockerfile với cú pháp riêng.

Container là một thực thể chạy của ảnh. Người dùng có thể tạo, khởi động, dừng hay xóa container sử dụng Docker API hoặc CLI. Container có thể kết nối tới một hoặc nhiều mạng khác nhau và gắn bộ lưu trữ vào. Mặc định thì container sẽ chạy cách li với các container khác cũng như máy đang chạy.

Hình 1.13: Kiến trúc chi tiết của Docker

Công nghệ được sử dụng phía dưới Docker bao gồm: namespace (giúp cách li tài nguyên sử dụng) và control group (giới hạn tài nguyên sử dụng) và Union File System (UnionFS, giúp tạo ra các lớp ảnh trong một ảnh docker hoàn chỉnh). Ảnh docker được đóng gói dựa vào libcontainer.

(31)

CHƯƠNG 2: YÊU CẦU CỦA HỆ THỐNG TRIỂN KHAI LIÊN TỤC

Có hai cách tiếp cận cơ bản đối với cơ sở hạ tầng dùng để triển khai dịch vụ:

cách thức sử dụng các máy một cách riêng rẽ và cách thức xem các máy như nhau, chỉ quan tâm tới số lượng máy (pet approach và cattle approach to infrastructure [11]).

Trong cách tiếp cận sử dụng các máy một cách riêng rẽ, mỗi máy được đặt tên riêng và các ứng dụng được phân bố tĩnh tới các máy. Ví dụ: Sử dụng máy tên db-prod để cài cơ sở dữ liệu. Các ứng dụng được triển khai thủ công trên các máy. Nếu máy triển khai có vấn đề, người sử dụng phải tự động sửa chữa hoặc chuyển toàn bộ ứng dụng sang máy khác. Cách tiếp cận này được sử dụng rộng rãi trước thời kỳ tính toán đám mây.

Với cách tiếp cận các máy được xem như giống hệt nhau và được đối xử như nhau, người dùng chỉ quan tâm tới số lượng máy sử dụng hơn là tên từng máy riêng lẻ, các ứng dụng được triển khai tự động trên bất kỳ máy nào. Khi một máy gặp vấn đề, người vận hành không cần sửa máy ngay lập tức mà sẽ có cơ chế để chuyển đổi ứng dụng từ máy đó sang các máy còn lại. Người vận hành sẽ thay thế máy tại thời điểm thích hợp chứ không phải ngay tại thời điểm máy hư.

Cách tiếp cận thứ hai thường được dùng cho các hệ thống dựa trên vi dịch vụ sử dụng container. Tuy nhiên, cách tiếp cận này đòi hỏi người triển khai phải lựa chọn cách thức cung ứng máy, làm thế nào để thiết lập kênh giao tiếp giữa các container với nhau cũng như với môi trường bên ngoài, làm thế nào để đảm bảo container được triển khai và có thể được tìm thấy trong một cluster các máy.

Để đảm bảo khả năng triển khai nhanh, một thiết kế triển khai liên tục cần phải thỏa mãn được yêu cầu nêu trên, cũng như các yêu cầu đa dạng khác để đảm bảo tính tiện dụng cho các bên liên quan. Chương này sẽ giới thiệu, phân tích những yêu cầu quan trọng nhất cho một hệ thống như vậy.

2.1 Yêu cầu về điều phối container 2.1.1 Khám phá dịch vụ

Trong các cách tiếp cận cơ sở hạ tầng dùng để triển khai dịch vụ, cách thức xem các máy như nhau thường được dùng trong các hệ thống vi dịch vụ sử dụng container.

Với cách tiếp cận này, các máy được đối xử một cách công bằng và người vận hành không phân phối các ứng dụng cụ thể lên các máy nhất định mà sử dụng các phần mềm lập lịch để quản lý vòng đời các ứng dụng (thường được đóng gói và triển khai

(32)

dưới dạng container). Tuy nhiên, yêu cầu đặt ra là làm cách nào người vận hành biết được container nào được triển khai trên máy nào bởi bộ lập lịch. Các công cụ khám phá dịch vụ được giới thiệu để giúp giải quyết vấn đề này.

Đối với các Docker container, vấn đề được thu gọn lại thành làm thế nào để có thể ánh xạ giữa container đang chạy và vị trí của nó. Vị trí ở đây chính là địa chỉ IP và cổng trên máy mà container được triển khai. Việc ánh xạ này cần được thực hiện một cách nhanh chóng và chính xác, bởi các container có thể được tắt hay bật lại trên các máy khác nhau trong cluster tại bất cứ thời điểm nào tùy thuộc vào môi trường.

Một giải pháp khám phá dịch vụ cần cung cấp được hai chức năng chính: [11]

Đăng kí: thiết lập ánh xạ giữa container và vị trí chạy khi container được triển khai. Bởi chỉ có bộ lập lịch biết chính xác vị trí mà container chạy, bộ lập lịch được xem như là nguồn đáng tin cậy duy nhất về vị trí container.

Tìm kiếm: Cho phép các container hay các dịch vụ ngoài tìm kiếm các ánh xạ của các container khác để có thể giao tiếp với chúng. Yêu cầu đối với việc tìm kiếm là thông tin cần chính xác và thời gian phản hồi nhanh.

2.1.2 Bộ lập lịch

Một bộ lập lịch cho hệ thống phân tán sẽ dựa vào yêu cầu của người dùng để xác định ứng dụng và triển khai nó trên một hoặc nhiều máy đang khả dụng.

Ví dụ: người dùng có thể gửi yêu cầu chạy nhiều bản sao của một ứng dụng nhất định, bộ lập lịch sẽ dựa vào thông tin về tài nguyên của các máy để phân bố triển khai ứng dụng một cách hợp lí. Đối với Docker, việc này đòi hỏi ảnh của ứng dụng phải có sẵn trên máy chuẩn bị triển khai và Docker phải được cài trên các máy đó.

Hình 2.1: Bộ lập lịch

Hình 2.1 thể hiện một ví dụ của lập lịch: người dùng yêu cầu triển khai ba bản

(33)

về trạng thái cluster, cách tận dụng tài nguyên các máy để đảm bảo bật đủ số lượng bản sao yêu cầu và làm thế nào để thỏa mãn các ràng buộc khác từ người dùng (Ví dụ:

chỉ triển khai ứng dụng trên máy có sử dụng ổ chứa SSD). Ngoài ra, chất lượng dịch vụ cũng là một yếu tố để đưa ra quyết định lựa chọn máy triển khai.

2.1.3 Điều phối container

Bộ lập lịch và chức năng khám phá dịch vụ đóng vai trò quan trọng trong việc quản lý container. Trên thực tế, hai thành phần này gần như luôn được sử dụng cùng nhau và nằm trong một khái niệm rộng hơn gọi là điều phối container [11].

Hình 2.2: Điều phối container và các thành phần

Hình 2.2 thể hiện các thành phần cơ bản của một nền tảng điều phối container như thành phần kiểm tra sức khỏe, tự động scale, thành phần khám phá dịch vụ, bộ lập lịch hay thành phần nâng cấp hệ thống. Nền tảng điều phối container sẽ thực hiện qúa trình khởi tạo, lập lịch, lựa chọn máy cho tới giám sát, cập nhật và đảm bảo giao tiếp của các container trong cluster.

(34)

Các nền tảng điều phối container khác nhau thường có nhiều đặc điểm khác nhau, nhưng tất cả những nền tảng này đều phải đảm bảo cung cấp được các tính năng cơ bản như:

Cách thức cấu hình đơn giản: Những nền tảng điều phối container thường cho phép người dùng khai báo các thông tin về cấu hình ứng dụng, kho ảnh, cấu hình về mạng và các cổng được mở trên máy, thông tin về bộ lưu trữ ... một cách đơn giản, trực quan thông qua các định dạng JSON hoặc YAML.

Có các API để bật tắt container: Nền tảng điều phối container sẽ có API cho phép việc cung ứng hay xếp lịch để bật container. Dựa vào các ràng buộc về tài nguyên, về mối tương quan của container cần bật với các container đang chạy khác mà các nền tảng điều phối sẽ chọn máy phù hợp để triển khai.

Có cơ chế khám phá dịch vụ: Khi triển khai một hệ thống gồm rất nhiều dịch vụ, các dịch vụ được đóng gói theo dạng ảnh container và chạy trên nhiều máy khác nhau thì việc một container có thể nhận biết các thông tin về container khác sẽ trở nên khó khăn và đây là một trong những việc quan trọng hàng đầu trong qúa trình quản lý toàn bộ cluster. Các nền tảng điều phối container đều cung cấp giải pháp để giải quyết vấn đề này cho người dùng, chẳng hạn thông qua các dịch vụ dạng DNS, dịch vụ proxy, ...

Cơ chế giám sát và sửa lỗi: Nền tảng điều phối container có trách nhiệm theo dõi, giám sát container cũng như các máy mà chúng đang chạy. Nếu container bị lỗi, việc bật một container mới để thay thế được thực hiện gần như ngay lập tức. Nếu một máy trong cluster bị lỗi, các container đang chạy trên máy đấy sẽ được phân phối để bật lại trên những máy còn lại. Thường thì người sử dụng sẽ miêu tả trạng thái container mong muốn thông qua file cấu hình (phổ biến nhất là dạng JSON hoặc YAML) còn nền tảng điều phối sẽ giám sát để luôn đảm bảo điều này.

Để đảm bảo xây dựng được hệ thống triển khai liên tục cho các phần mềm dựa trên vi dịch vụ, yêu cầu đầu tiên chính là việc lựa chọn nền tảng điều phối container thỏa mãn những tính chất đã nêu trên, phù hợp với cơ sở hạ tầng mà tổ chức đang sử dụng, có nhiều công cụ hỗ trợ cũng như có khả năng mở rộng tốt trong tương lai.

2.2 Yêu cầu cho các nhà phát triển 2.2.1 Khả năng tự triển khai

Ngoài việc tự động triển khai khi có sự thay đổi mã nguồn trên kho mã chung, hệ thống triển khai liên tục cũng cần có cơ chế để cho phép các đội phát triển, kiểm thử tự triển khai ứng dụng lên các môi trường, phục vụ mục đích kiểm tra tính năng hoặc

(35)

kiểm thử, tái hiện lỗi. Hệ thống phân quyền cần được cấu hình để đảm bảo quyền hạn khác nhau tùy theo vai trò của các đội.

2.2.2 Nhận được các thông tin về kết quả build

Quá trình triển khai liên tục thường gồm hai giai đoạn: dịch và triển khai. Dịch là quá trình biên dịch từ mã nguồn để đưa ra được một phiên bản chạy của ứng dụng, còn triển khai sẽ sử dụng sản phầm của quá trình dịch để cập nhật lên môi trường. Trách nhiệm của các đội phát triển là phải đảm bảo build thành công đối với bất cứ sự thay đổi mã nào. Tuy nhiên, quá trình dịch thường mất thời gian và các lập trình viên thường bận rộn với việc phát triển tính năng mới cho sản phẩm, do vậy cần có cơ chế để thông báo trạng thái của các tác vụ dịch cho các đội thông qua các kênh giao tiếp của công ty như email, phần mềm chat, ...

2.3 Yêu cầu về vận hành 2.3.1 Quản lý cấu hình

Cơ sở hạ tầng được quản lý như mã (Infrastructure as code - IAC) là cách tiếp cận việc tự động hóa quản lý cơ sở hạ tầng dựa trên những kinh nghiệm từ quá trình phát triển phần mềm [12]. IAC nhấn mạnh vào tính nhất quán, lặp đi lặp lại đối với việc cung ứng và thay đổi các hệ thống cũng như cấu hình của chúng. Ý tưởng của IAC là người dùng sẽ viết và thực thi mã để định nghĩa, triển khai và cập nhật cơ sở hạ tầng. IAC thay đổi nhận thức của mọi người trong việc đối xử các hoạt động vận hành như là phần mềm, dù một số hoạt động thực tế liên quan tới phần cứng (ví dụ: cài đặt máy chủ triển khai).

Bằng việc ứng dụng IAC, không chỉ người quản trị, bất cứ ai cũng có thể đọc và hiểu về toàn bộ cấu hình hệ thống, có khả năng đảo ngược cấu hình về phiên bản chạy tốt bằng việc sử dụng hệ thống quản lí phiên bản. IAC cũng cho phép đánh giá, kiểm thử trước khi thực sự triển khai sự thay đổi về cơ sở hạ tầng.

Hệ thống quản lý cấu hình là một dạng công cụ IAC. Các hệ thống công nghệ thông tin thường xuyên thay đổi. Với mỗi bản phát hành, để hệ thống hoạt động được, người vận hành có thể cần thay đổi một số cấu hình nhất định. Trong hệ thống triển khai liên tục, tần suất triển khai cao có thể khiến cấu hình của cơ sở hạ tầng ngày một khác biệt so với trạng thái ban đầu, trở nên khó quản lý và lộn xộn. Nhằm tránh tình trạng không nhất quán này, cần có một hệ thống quản lý cấu hình phù hợp.

2.3.2 Thu thập và lưu trữ log

Thu thập và lưu trữ log là yêu cầu cơ bản đối với bất cứ hệ thống phần mềm thực tế nào [13].

(36)

Trong một hệ thống vi dịch vụ dựa vào container, các container sẽ được triển khai trong một cluster gồm nhiều máy. Với mỗi máy, ngoài các container còn có những dịch vụ khác đang chạy. Các ứng dụng sẽ sản sinh ra các tệp log với định dạng, vị trí khác nhau, khiến cho việc quản lý và sử dụng log trở nên khó khăn [14] (Hình 2.3).

Hình 2.3: Cách thức thu thập log trước đây

Cần có cơ chế để thu thập toàn bộ log cho tất cả các ứng dụng hay container này, đồng thời cho phép người dùng sử dụng chúng một cách hiệu quả: ví dụ như việc sau khi thu thập, sẽ có quá trình phân loại log, đánh chỉ số và cho phép người dùng tìm kiếm trên một giao diện phù hợp.

2.3.3 Giám sát và thông báo lỗi

Các nền tảng điều phối container có cơ chế giám sát để đảm bảo các dịch vụ hoạt động bình thường và có phương pháp sửa lỗi nếu phát hiện vấn đề. Tuy nhiên, cơ chế cung cấp bởi nền tảng điều phối container thường chỉ ở mức cơ bản.

Ví dụ: các dịch vụ cung cấp một API luôn trả lại mã trạng thái 200 (HTTP CODE), thành phần giám sát trong điều phối container sẽ gửi yêu cầu tới API này một cách định kỳ, nếu kết quả trả lại khác 200 thì thành phần giám sát sẽ thông báo tới bộ lập lịch để tắt và bật lại dịch vụ đó.

Gambar

Hình  1.1: Các bước cơ bản trong tích hợp liên tục [5]
Hình  1.2 thể hiện sự so sánh của ba kiểu kiến trúc nêu trên về khả năng co dãn  (scale) và sự tách biệt của các thành phần trong hệ thống
Hình  1.3: Kiến trúc một khối cho ứng dụng đặt hàng  Ưu điểm của kiến trúc này bao gồm:
Hình  1.4: Kiến trúc hướng dịch vụ cho ứng dụng đặt hàng  1.3.3  Kiến trúc vi dịch vụ
+7

Referensi

Dokumen terkait

Trong những năm 1939 – 1945, đặc biệt khi cuộc chiến tranh bước vào giai đoạn các nước Đồng Minh giành thế chủ động, báo chí cách mạng của Trung Kỳ đã theo sát những diễn biến quan

Phương pháp nghiên cứu: - Các phương pháp công nghệ thích hợp để chế tạo các vật liệu chứa chuyển tiếp dị chất cấu trúc nanô, đó là: tổng hợp sol-gel sử dụng các chất tiền tố cầu nối

Một mô hình ứng dụng phân lớp đa nhãn văn bản bán giám sát Thừa hưởng các kết quả thu được từ các mô hình biểu diễn dữ liệu theo chủ đề ẩn đã trình bày ở Chương 3 nhằm khai thác các

Đề xuất ba thuật toán tìm các tập hiếm cho ba dạng luật hiếm là: thuật toán MCPSI phát hiện tập Sporadic tuyệt đối hai ngưỡng, MCISI phát hiện tập Sporadic không tuyệt đối hai ngưỡng và

Các dịch vụ ngang hàng Ionic có các trình cắm hỗ trợ các kết nối ngang hàng sử dụng các giao diện WebRTC hoặc bluetooth Xamarin hỗ trợ tương tự iOS Đồ hoạ Bắt buộc sử dụng GPU để đảm

1.3 Các ứng dụng của khai phá dữ liệu phương tiện vận tải Luận văn này tập trung vào mảng ứng dụng “Dịch vụ Giám sát và điều khiển giao thông” – là một nhu cầu bức thiết hiện nay để

Tóm tắt các kết quả của luận văn: Luận văn trình bày về phương pháp phân tích sự ảnh hưởng của các thành phần trong mã nguồn Java và mở rộng phân tích ảnh hưởng của các thành phần giao

Dựa trên lý thuyết tấm cổ điển, biến dạng trượt bậc nhất và bậc ba của Reddy cùng với tính phi tuyến hình học của Von Karman kết hợp với kỹ thuật san đều tác dụng gân của Lekhnitskii và