1. Trang chủ
  2. » Luận Văn - Báo Cáo

TỰ ĐỘNG HOÁ QUÁ TRÌNH XÂY DỰNG DOCKER CONTAINER VỚI ANSIBLE

79 105 3

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 79
Dung lượng 4,53 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Tự động hoá việc cài đặt Docker và xây dựng cấu hình DNS Consul bằng Ansible trên nền tảng Docker. Xây dựng tự động DNS Consul có khả năng phân giải tên miền nội bộ của các dịch vụ và node. Phát hiện dịch vụ tự động bằng Consul thành công. Các công cụ thực hiện: Ansible, Docker, Registrator, Domain name system.

Trang 1

BỘ THÔNG TIN VÀ TRUYỀN THÔNG HỌC VIỆN CÔNG NGHỆ BƯU CHÍNH VIỄN THÔNG

-BÁO CÁO ĐỒ ÁN TỐT NGHIỆP ĐẠI HỌC

Hệ : ĐẠI HỌC CHÍNH QUY

TP.HCM, tháng 12/2019

Trang 2

Báo cáo DATN Đại Học

Lời cảm ơn

LỜI CẢM ƠN

Trong thời thời gian học tập và hoàn thành đồ án tốt nghiệp “Tự động hoá quá trình xâyDocker container với Ansible” em luôn nhận được sự giúp đỡ tận tình của thầy hướng dẫn,quý thầy cô trong khoa Công nghệ Thông tin 2 và các bạn

Lời đầu tiên em xin được gửi lời cảm ơn trân trọng tới thầy, TS Nguyễn Hồng Sơn,người đã tận tâm hướng dẫn em trong quá trình hoàn thành đồ án Thầy luôn tận tâm truyềnđạt kiến thức mới và giúp em giải đáp các vấn đề còn thiếu sót trong nhiệm vụ được giao.Đồng thời em cũng xin chân thành cảm ơn quý thầy cô trong khoa Công nghệ thông tin 2

đã chỉ bảo và tạo mọi điều kiện để em có thể hoàn thành đồ án tốt nghiệp này

Tuy đã nỗ lực thực hiện đề tài được giao nhưng do thời gian có hạn và kiến thức chưa đầy

đủ, nên bài báo cáo còn nhiều thiếu sót, em mong nhận được sự thông cảm và lời góp ý từ quýthầy cô cùng các bạn để đề tài được hoàn thiện hơn

Em xin kính chúc quý thầy cô dồi dào sức khoẻ và thành công trong sự nghiệp cao quý.Chúc các bạn sớm đạt được nguyện vọng và thành đạt trong cuộc sống

Một lần nữa em xin chân thành cám ơn!

TPHCM, tháng 12 năm 2019Sinh viên thực hiện

Trang 3

Báo cáo DATN Đại Học

Mục lục

MỤC LỤC

MỞ ĐẦU 1

LÝ THUYẾT VỀ DOCKER 2

TỰ ĐỘNG HOÁ IT AUTOMATION VỚI ANSIBLE 17

GIẢI PHÁP CONSUL 30

THỰC HÀNH TỰ ĐỘNG HOÁ XÂY DỰNG DNS CONSUL BẰNG ANSIBLE TRÊN NỀN TẢNG DOCKER CONTAINER 42

KẾT LUẬN 72

TÀI LIỆU THAM KHẢO 73

Trang 4

Báo cáo DATN Đại Học

Danh mục các ký hiệu và từ viết tắt

DANH MỤC CÁC KÝ HIỆU VÀ TỪ VIẾT TẮT

API: Application Programming Interface Giao diện lập trình ứng dụng

DSL: Domain Specific Language Ngôn ngữ đặc tả chuyên biệt

HTTP: Hypertext Transfer Protocol Giao thức truyền tin siêu văn bản

TCP: Transmission Control Protocol Giao thức điều khiển truyền tin

YAML: YAML Ain't Markup Language Ngôn ngữ tuần tự hoá dữ liệu

Trang 5

Báo cáo DATN Đại Học

Danh mục các bảng, sơ đồ, hình ảnh

DANH MỤC CÁC BẢNG, SƠ ĐỒ, HÌNH ẢNH

Hình 1.1 Mô hình máy chủ cổ điển 2

Hình 1.2 Mô hình máy chủ sử dụng công nghệ ảo hoá 5

Hình 1.3 Mô hình máy chủ sử dụng công nghệ containerlization 5

Hình 1.4 Docker Engine 6

Hình 1.5 REST API 8

Hình 1.6 Hoạt động của API 9

Hình 1.7 Kiến trúc của Docker 10

Hình 1.8 Quy trình tạo ra Docker Container 12

Hình 1.9 Thông tin Docker network mode bridge 15

Hình 1.10 Thông tin Docker network mode User-defined bridge 16

Hình 2.11 So sánh các công cụ Automation 17

Hình 2.12 Độ phổ biến của các công cụ Automation 18

Hình 2.13 Kiến trúc hoạt động của Ansible 21

Hình 2.14 So sánh các Data Model 21

Hình 2.15 Sự khác nhau giữa Dictionary và Array/List trong YAML 23

Hình 2.16 Ansible Role 29

Hình 3.17 Khó khăn của việc truy tìm dịch vụ trong ứng dụng Microservices 32

Hình 3.18 Client-side Discovery 33

Hình 3.19 Server-side Discovery 35

Hình 3.20 Giao tiếp trong một cụm Consul Datacenter 38

Hình 3.21 Giao tiếp giữa nhiều cụm Consul Datacenter 40

Hình 4.22 Hệ thống phân cấp DNS - DNS Hierachy 43

Hình 4.23 File cấu hình Ansible - ansbile.cfg 44

Hình 4.24 File Inventory - hosts 44

Hình 4.25 Playbook cấu hình Server node - server.yml 45

Hình 4.26 Playbook cấu hình Agent node – agent.yml 45

Hình 4.27 Playbook cấu hình Registrator – registrator.yml 46

Hình 4.28 Playbook tạo Service trên Client – service.yml 47

Hình 4.29 Playbook tạo Service trên Server – service.yml 47

Hình 4.30 Playbook kiểm tra kết quả DNS nslookup - test.yml 49

Hình 4.31 Playbook kiểm tra kết quả DNS dig – test.yml 50

Hình 4.32 Thư mục Docker roles 50

Hình 4.33 Docker roles - /tasks/main.yml (1) 52

Hình 4.34 Docker roles - /tasks/main.yml (2) 52

Hình 4.35 Thư mục Consul roles 53

Hình 4.36 File biến mặc định - /defaults/main.yml 53

Hình 4.37 File jinja2 cấu hình Consul Server - /templates/server.json.j2 54

Trang 6

Báo cáo DATN Đại Học

Danh mục các bảng, sơ đồ, hình ảnh

Hình 4.38 File jinja2 cấu hình Consul Agent - /templates/agent.json.j2 55

Hình 4.39 File jinja2 cấu hình dnsmasq - /templates/10-consul.j2 55

Hình 4.40 Consul Role cấu hình Consul Server - /tasks/server.yml 56

Hình 4.41 Consul Role cấu hình Consul Agent - /tasks/agent.yml 56

Hình 4.42 Consul Role cấu hình dnsmasq - /tasks/dnsmasq.yml 57

Hình 4.43 Consul Role cấu hình tổng hợp - /tasks/main.yml 59

Hình 4.44 Thư mục Ansbile trên server ansbile 60

Hình 4.45 Run playbook server.yml (1) 61

Hình 4.46 Run playbook server.yml (2) 61

Hình 4.47 Run playbook agent.yml (1) 62

Hình 4.48 Run playbook agent.yml (2) 62

Hình 4.49 Run playbook registrator.yml 63

Hình 4.50 Run playbook service.yml 63

Hình 4.51 Docker container trên server ansible 63

Hình 4.52 Docker container trên agent ansbile_1 63

Hình 4.53 Consul members 64

Hình 4.54 Consul node 64

Hình 4.55 Consul Service 65

Hình 4.56 Service nginx trên host ansible 65

Hình 4.57 Service httpd trên host ansible_1 66

Hình 4.58 Kiểm tra tự động bằng playbook test.yml (1) 66

Hình 4.59 Kiểm tra tự động bằng playbook test.yml (2) 67

Hình 4.60 Kiểm tra tự động bằng playbook test.yml (3) 67

Hình 4.61 Kiểm tra tự động bằng playbook test.yml (4) 68

Hình 4.62 Kiểm tra tự động bằng playbook test.yml (5) 69

Hình 4.63 Kiểm tra thủ công trên host ansbile - nslookup 69

Hình 4.64 Kiểm tra thủ công trên host ansbile - ping (1) 70

Hình 4.65 Kiểm tra thủ công trên host ansbile - ping (2) 70

Hình 4.66 Kiểm tra thủ công trên host ansbile - dig 70

Hình 4.67 Kiểm tra thủ công trên host ansbile_1 - nslookup 71

Hình 4.68 Kiểm tra thủ công trên host ansbile_1 - ping (1) 71

Hình 4.69 Kiểm tra thủ công trên host ansbile_1 - ping (2) 71

Hình 4.70 Kiểm tra thủ công trên host ansbile_1 – dig 71

Trang 7

Báo cáo DATN Đại Học

Mở đầu

MỞ ĐẦU

Ngày nay với sự phát triển vũ bão của công nghệ thông tin thì nhu cầu sử dụng các máytính ngày càng nhiều, tuy nhiên với cách xây dựng máy tính cổ điển đã không tận dụng đượctối đa các tài nguyên sẵn có, từ đó các công nghệ ảo hoá ra đời Ảo hoá tạo ra các VM (VirtualMachine) có các hệ điều hành khác nhau nhưng vẫn có sự tiêu tốn tài nguyên được cấp phátcho chúng Công nghệ Containerlization đóng gói các ứng dụng thành các container tận dụngtối đa khi chia sẻ tài nguyên với máy chủ vật lý Docker là một trong các dự án mã nguồn mởcho phép phát triển, đóng gói, thực thi các ứng dụng thành các container

Tuy nhiên thực hiện cấu hình và quản lý các container và số lượng máy tính lớn gây raviệc phải lặp đi lặp lại nhiều thao tác giống nhau Các công cụ tự động hoá Automation giúpchúng ta thực hiện điều này dễ dàng, nhanh chóng và tập trung hơn Trong đó Ansible là công

cụ nổi bật hơn hết với tính tiện dụng và dễ dàng tiếp cận Đây chính là lý do em chọn đề tài

“Tự động hoá quá trình xây dựng Docker Container với Ansible”

Nội dung chính của đồ án tốt nghiệp bao gồm các mục sau:

Chương 1: Lý thuyết về Docker

Chương 2: Tự động hoá IT Automation với Ansible

Chương 3 Giải pháp Consul

Chương 4: Thực hành tự động hoá xây dựng DNS Consul bằng Ansible trên nền tảng DockerContainer

Trang 8

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker

Trang 9

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về DockerNhưng cách xây dựng máy chủ này gây lãng phí tài nguyên khi không thể tận dụng tàinguyên về CPU, RAM, dung lượng lưu trữ và chỉ chạy một hệ điều hành Từ đó công nghệ ảohoá ra đời

Trang 10

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker INCLUDEPICTURE "https://viblo.asia/uploads/f83e4a3a-bc95-4a4d-af37-

dbaa9e03d28f.png" \* MERGEFORMATINET INCLUDEPICTURE

Trang 11

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker

Hình 1.2 Mô hình máy chủ sử dụng công nghệ ảo hoá

Với công nghệ này, trên một máy chủ vật lý có thể tạo ra nhiều máy ảo với hệ điều hànhkhác nhau nhưng đồng thời cũng nảy sinh vấn đề về việc lãng phí khi cấp phát tài nguyên chocác máy ảo Vì vậy, người ta tạo ra công nghệ containerlization Công nghệ này cho phép trênmột máy chủ vật lý sẽ sinh ra các máy con nhưng được tối ưu hơn khi các máy con dùngchung hệ điều hành và chia sẻ tài nguyên với máy chủ vật lý Việc cấp phát tài nguyên chocác container sẽ được thực hiện theo nhu cầu và được tối ưu hơn

Hình 1.3 Mô hình máy chủ sử dụng công nghệ containerlization

1.2 Container

Các ứng dụng sẽ được Container Engine (công cụ ảo hoá đặt trên host OS) đóng góithành các container Container là giải pháp chuyển giao ứng dụng một cách tin cậy giữa cácmáy tính khác nhau bằng cách: Tạo ra môi trường chứa tất cả các điều kiện cần thiết để chạyứng dụng đó, không bị các yếu tố ảnh hưởng và làm ảnh hưởng đến hệ thống Các tiến trình(process) trong một container bị cô lập với các container khác cùng hệ thống nhưng chia sẻhost OS với nhau

Ưu điểm:

• Linh động: có thể triển khai ở bất kỳ đâu do không có sự phụ thuộc vào OS và các nềntảng vật lý

• Việc thực thi các container nhanh hơn do dùng chung OS với máy chủ vật lý

• Không tiêu tốn quá nhiều dung lượng

• Không xảy ra sự sai khác về môi trường khi thực hiện dự án nhóm

• Việc thực thi hay loại bỏ các container dễ dàng hơn khi các chương trình đã được đónggói vào một container

1.3 Docker

Docker là một nền tảng mở cho phép phát triển, đóng gói, thực thi các ứng dụng thànhcác Container Nó có thể xây dựng, chuyển giao và thực thi ứng dụng trên các nền tảng màDocker có thể được cài đặt và làm việc trên đó

Trang 12

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker

1.3.1 Các thành phần chính

1.3.1.a Docker Engine

Docker Engine là công cụ Client - Server hỗ trợ công nghệ container để xử lý các nhiệm

vụ và quy trình công việc liên quan đến việc xây dựng các ứng dụng dựa trên vùng chứa(container) Engine tạo ra một quy trình daemon phía máy chủ lưu trữ images, containers,networks và storage volumes Daemon cũng cung cấp giao diện dòng lệnh phía máy khách(CLI) cho phép người dùng tương tác với daemon thông qua giao diện lập trình ứng dụngDocker

Hình 1.4 Docker Engine

- Images: là thành phần để đóng gói ứng dụng và các thành phần mà ứng dụng phụ thuộc đểchạy Và image được lưu trữ ở trên local hoặc trên một Registry (là nơi lưu trữ và cung cấpkho chứa các image)

- Containers: là một instance của image, và nó hoạt động như một thư mục, chứa tất cảnhững thứ cần thiết để chạy một ứng dụng

- Network: cung cấp một mạng riêng chỉ tồn tại giữa container và host

- Volume: Volume trong Docker được dùng để chia sẻ dữ liệu cho container

• Rest API (RESTful API):

REST là viết tắt của Representational State Transfer Giải thích đơn giản, REST là mộtloạt hướng dẫn và dạng cấu trúc dùng cho việc chuyển đổi dữ liệu Thông thường, REST hayđược dùng cho ứng dụng web, nhưng cũng có thể làm việc được với dữ liệu phần mềm API

là viết tắt của Application Programming Interface, phương thức kết nối với các thư viện vàứng dụng khác REST API là một ứng dụng chuyển đổi cấu trúc dữ liệu có các phương thức

Trang 13

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker INCLUDEPICTURE "https://i0.wp.com/movan.vn/wp-content/uploads/2019/04/RESTful-API-design-1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

1014x457.jpg?resize=806,363" \* MERGEFORMATINET INCLUDEPICTURE

Trang 14

"https://i0.wp.com/movan.vn/wp-content/uploads/2019/04/RESTful-API-design-Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker1014x457.jpg?resize=806,363" \* MERGEFORMATINET

Hình 1.5 REST API

Nhìn chung, có bốn lệnh dùng để truy cập RESTful API:

• GET để truy vấn object

• POST để tạo object mới

• PUT để sửa đổi hoặc thay thế một object

• DELETE để loại bỏ một object

Mỗi phương thức trên phải được API call thông qua để gửi chỉ thị cho server phải làm gì

Trang 15

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker INCLUDEPICTURE "http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-

diagram-api.jpg" \* MERGEFORMATINET INCLUDEPICTURE

"http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \*MERGEFORMATINET INCLUDEPICTURE "http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \* MERGEFORMATINET INCLUDEPICTURE

"http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \*MERGEFORMATINET INCLUDEPICTURE "http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \* MERGEFORMATINET INCLUDEPICTURE

"http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \*MERGEFORMATINET INCLUDEPICTURE "http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \* MERGEFORMATINET INCLUDEPICTURE

"http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \*MERGEFORMATINET INCLUDEPICTURE "http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \* MERGEFORMATINET INCLUDEPICTURE

"http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \*MERGEFORMATINET INCLUDEPICTURE "http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \* MERGEFORMATINET INCLUDEPICTURE

"http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \*MERGEFORMATINET INCLUDEPICTURE "http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \* MERGEFORMATINET INCLUDEPICTURE

"http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \*MERGEFORMATINET INCLUDEPICTURE "http://media02.hongkiat.com/rest-restful-api-dev/01-restful-rest-diagram-api.jpg" \* MERGEFORMATINET INCLUDEPICTURE

Trang 16

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker

1.3.1.c Orchestration tool (công cụ điều phối)

• Docker Machine: Machine tạo Docker Engine trên máy tính hoặc trên bất cứ dịch vụcloud phổ biến nào như AWS, Azure, Google Cloud, Softlayer hoặc trên hệ thống datacenter như VMware, OpenStack Docker Machine sẽ tạo các máy ảo và cài Docker Enginelên chúng và cuối cùng nó sẽ cấu hình Docker Client để giao tiếp với Docker Engine mộtcách bảo mật

• Docker Compose: là công cụ giúp định nghĩa và khởi chạy multi-container Dockerapplications

• Docker Swarm: là một công cụ giúp chúng ta tạo ra một clustering Docker Nó giúp chúng

ta gom nhiều Docker Engine lại với nhau như duy nhất một virtual Docker Engine

1.3.2 Kiến trúc của Docker

Hình 1.7 Kiến trúc của Docker

Docker sử dụng kiến trúc client-server Docker client sẽ liên lạc với các Docker daemon,các Docker daemon sẽ thực hiện các tác vụ build, run và distributing các Docker container CảDocker client và Docker daemon có thể chạy trên cùng 1 máy, hoặc có thể kết nối theo kiểuDocker client điều khiển các docker daemon như hình trên Docker client và daemon giao tiếpvới nhau thông qua socket hoặc RESTful API Docker daemon chạy trên các máy Dockerhost Người dùng sẽ không tương tác trực tiếp với các Daemon, mà thông qua Docker Client

1.3.3 Lợi ích của việc sử dụng Docker

• Thay thế cho các máy ảo: Docker có thể được thay thế cho các máy ảo trong nhiều tìnhhuống:

- Nếu chỉ quan tâm đến ứng dụng mà không quan tâm đến hệ điều hành, việc sử dụngDocker sẽ loại bỏ việc sử dụng máy ảo và không phải quan tâm đến môi trường làm việc

- Docker chạy nhanh hơn và nhẹ hơn nhiều so với các máy ảo, vì vậy có thể dễ dàng chuyểngiao, chia sẻ với người dùng khác

Trang 17

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker

• Tạo nên một kiến trúc microservices: Docker tạo điều kiện để phân rã một hệ thống phứctạp thành nhiều bộ phận khác nhau, cho phép tái cấu trúc phần mềm để dễ dàng quản lýhơn mà không làm ảnh hưởng đến các toàn bộ

• Tạo mô hình mạng: Docker có thể tạo ra hàng trăm các container độc lập với nhau, điềunày có thể dễ dàng giả lập một kịch bản mô hình mạng mà không ảnh hưởng đến mạngthật

• Giảm thiểu việc gỡ lỗi trong quá trình chuyển giao phần mềm: Quá trình chuyển giao phầnmềm có thể xảy ra sai sót khi có sự phụ thuộc của môi trường, thư viện, thứ tự sai Dockercho phép liệt kê tất cả các bước để làm cho việc gỡ lỗi trở nên dễ dàng hơn nhiều

• Continuous Delivery (CD)

CD là một mô hình phân phối phần mềm trong chu kỳ ngắn, đảm bảo rằng các phần mềm

có thể được phát hành một cách tự động hoặc tự động một phần Nó nhằm mục đích xâydựng, kiểm thử, và phát hành phần mềm nhanh hơn và thường xuyên hơn Cách tiếp cận nàygiúp giảm chi phí, thời gian và nguy cơ khi thay đổi bằng cách gia tăng cập nhật các ứng dụngtrong sản phẩm

Docker có thể thay thế phương pháp xây dựng phần mềm truyền thống, điều này làm choviệc thực hiện CD dễ dàng hơn Các kỹ thuật CD tiêu chuẩn có thể được thay thế bởi thựchiện quy trình của Docker

1.3.4 Các câu lệnh cơ bản

• Pull một image từ Docker Hub

sudo docker pull image_name

• Chạy một container

sudo docker run -v <forder_in_computer>:<forder_in_container> -p

<port_in_computer>:<port_in_container> -it <image_name> /bin/bash

• Một số câu lệnh khác

- Liệt kê các images hiện có: docker images

- Xóa một image: docker rmi {image_id/name}

- Liệt kê các container đang chạy: docker ps

- Liệt kê tất cả các container : docker ps -a

- Xóa một container: docker rm -f {container_id/name}

- Khởi động một container: docker start {new_container_name}

- Truy cập vào container đang chạy: docker exec -it {new_container_name} /bin/bash

1.3.5 Docker file

Dockerfile là file giúp thiết lập cấu trúc cho docker image nhờ chứa một tập hợp các câulệnh Quá trình tạo ra một container được thể hiện ở hình dưới

Trang 18

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker INCLUDEPICTURE "https://images.viblo.asia/751d7512-c9e7-44a5-be56-

6b1ff9096adf.png" \* MERGEFORMATINET INCLUDEPICTURE

Trang 19

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker

• Cài đặt ứng dụng, thiết lập môi trường

- RUN : Để thực thi một câu lệnh nào đó trong quá trình build images

- CMD : Để thực thi một câu lệnh trong quá trình bật container Mỗi Dockerfile chỉ có mộtcâu lệnh CMD, nếu như có nhiều hơn một câu lệnh CMD thì chỉ có câu lệnh CMD cuốicùng được sử dụng

- ENTRYPOINT: Để thực thi một số câu lệnh trong quá trình start container, những câu lệnhnày sẽ được viết trong file sh

• Cấu hình

- EXPOSE: Container sẽ lắng nghe trên các cổng mạng được chỉ định khi chạy

- ADD : Copy file, thư mục, remote file thêm chúng vào filesystem của image

- COPY : Copy file, thư mục từ host machine vào image Có thể sử dụng url cho tập tin cầncopy

- WORKDIR : Định nghĩa thư mục cho CMD

- VOLUME : Mount thư mục từ máy host vào container

RUN apt-get update

RUN apt-get install -y nginx

RUN echo "mysql-server mysql-server/root_password password root" | selections \

&& echo "mysql-server mysql-server/root_password_again password root" | debconf-set-selections \

&& apt-get install -y mysql-server

WORKDIR /nginx

COPY start.sh /nginx

RUN chmod a+x /nginx/*

ENTRYPOINT ["/nginx/start.sh"]

EXPOSE 80

File: hello.html

<h1>Hello word</h1>

• Build Image từ dockerfile

sudo docker build -t <image_name>

Ví dụ: sudo docker build –t ubuntu-nginx

• Run container

Trang 20

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker

sudo docker run -v <forder_in_computer>:<forder_in_container> -p

<port_in_computer>:<port_in_container> -it <image_name> /bin/bash

Trong đó:

-v : Thể hiện việc mount volume, dữ liệu từ thư mục từ máy thật có thể được truy cập từ thưmục của máy ảo

-p: Cổng mạng từ máy thật để dẫn tới cổng mạng của máy ảo đang chạy

-t: Chạy container và mở terminal bằng /bin/bash

Ví dụ:

Sudo docker run –v /test: /var/www/html –p 9000:80 ubuntu-nginx /bin/bash

1.3.6 Network mode trong Docker

Khi cài đặt Docker, mặc định 3 mạng được tạo ra

# docker network ls

Ba mạng này đều là thành phần mặc định của Docker Khi chạy 1 container có tuỳ chọn network thì nó sẽ chỉ định trực tiếp mạng mà container chạy trên đó:

- Bridge: là mạng mặc định chạy với Docker nếu không có tuỳ chọn network đi cùng

- None: Nó hoàn toàn tắt card mạng đi

- Host: là mạng chỉ gắn container với host ngoài Container có cấu hình mạng giống nhưhost, thường sẽ là card loopback

• Default Bridge network

Default bridge network được hiện diện trên tất cả các Docker hosts Câu lệnh dockernetwork inspect trả lại các thông tin về network:

Trang 21

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker

Hình 1.9 Thông tin Docker network mode bridge

Câu lệnh docker network inspect hiển thị toàn bộ các container được kết nối và networkresources của loại network được truyền vào Containers trong default network có thể giao tiếpvới nhau bằng IP addresses Docker không hỗ trợ tự động quét service trên default bridgenetwork Nếu muốn giao tiếp thông qua container names trong default bridge network phảikết nối các containers với nhau thông qua tuỳ chọn docker run link

• User-defined network

user-defined network dễ dàng tạo ra nhất là bridge network Network này tương tự defaultdocker0 network

Trang 22

Báo cáo DATN Đại Học

Chương 1 Lý thuyết về Docker

Hình 1.10 Thông tin Docker network mode User-defined bridge

Sau khi tạo ra network, các containers có thể chạy trên đó bằng cách sử dụng tuỳ chọn docker

run network=<NETWORK>

Trong mạng tự xác định, link không được hỗ trợ và phải public port trên mạng này ra ngoài.

Trang 23

Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

TỰ ĐỘNG HOÁ IT AUTOMATION VỚI ANSIBLE

1.4 Tự động hoá

Tự động hoá IT automation hay còn được gọi là tự động hoá hạ tầng Infrastructureautomation là việc sử dụng phần mềm để tạo ra các hướng dẫn và quy trình lặp lại để thay thếhoặc giảm sự tương tác của con người với các hệ thống công nghệ thông tin Phần mềm tựđộng hóa hoạt động trong giới hạn của các chỉ dẫn, công cụ và framework để thực hiện cácnhiệm vụ mà không cần sự can thiệp của con người

Có nhiều công cụ quản lý cấu hình tự động như Chef, Puppet, Saltstack, Ansible

+ Chef: có kiến trúc master - agent, chef server chạy trên máy master và chef client chạy như

là agent trên mỗi máy client Thêm vào đó là workstation chứa các cấu hình được kiểm tra

và đẩy lên chef server

+ Puppet: tương tự như Chef có kiểu kiến trúc master – agent Puppet server chạy trên máymaster, và Puppet client chạy trên máy client Thêm vào đó phải có chứng chỉ đăng nhậpgiữa master và agent

+ Ansible: đơn giản hơn khi chỉ có một master chạy trên máy server và dùng kết nối ssh đểđăng nhập vào hệ thống client muốn cấu hình

+ Saltstack: Server được gọi là salt master và clients được gọi là salt minions

- Ngôn ngữ sử dụng

+ Chef sử dụng Ruby DSL nên người sử dụng phải biết về lập trình

+ Puppet không dễ quản lý khi nó sử dụng ngôn ngữ riêng Puppet DSL (Domain SpecificLanguage)

+ Ansible có thể dễ dàng sử dụng và quản lý bởi nó sử dụng YAML (YAML Ain't MarkupLanguage) gần với ngôn ngữ tự nhiên, máy chủ sẽ đẩy cấu hình tới các node

Trang 24

Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

+ Saltstack tương tự như Ansible do cùng sử dụng YAML, máy chủ sẽ đẩy cấu hình đến cácclient

- Khả năng mở rộng: tất cả đều có khả năng mở rông cao do máy chủ được chạy trên hệ điềuhành Unix/Linux nhưng các máy client có thể hoạt động được trên windows

- Phổ biến

Hình 2.12 Độ phổ biến của các công cụ Automation

1.5 Tại sao phải thực hiện tự động

Với sự phát triển nhanh chóng của Internet, Cloud computing trở nên phổ biến hơn, cácdịch vụ điện toán đám mây như Amazon Web Service AWS có hàng triệu người dùng và cungcấp nền tảng cho doanh nghiệp và người dùng cá nhân

Tuy nhiên, dù điện toán đám mây dần chiếm ưu thế hơn so với loại truyền thống nhưngcác dịch vụ vẫn cần được cài đặt và cấu hình thủ công

Việc cài đặt, cấu hình các dịch vụ phải được diễn ra càng nhanh càng tốt Thời gianngừng hoạt động và cập nhật có thể bị kéo dài nếu các tiến trình diễn ra Vì vậy mà việc cấuhình và quản lý tự động được phát triển nhằm giúp cho các kỹ sư, đồng thời cũng giảm chiphí khi dịch vụ ngừng hoạt động Đặc biệt là các công ty có hàng nghìn server sẽ tốn rất nhiềuthời gian để cập nhật các cấu hình Việc giảm thiểu chi phí của thời gian tạm ngừng hoạtđộng, cấu hình, cập nhật có hiệu quả hơn đã khiến nó càng ngày phổ biến hơn với các công tylớn

Việc tự động hoá có thể sử dụng cho nhiều mục đích, ở đây Ansible có thể được sử dụngcho việc cung cấp dịch vụ cloud, quản lý cấu hình tự động, triển khai ứng dụng, điều phối cácdịch vụ… Mục đích khác của tự động hoá đơn giản là cập nhật hệ thống và phần mềm, nângcấp dịch vụ hoặc cài đặt lại

1.6 Ansible

Ansible là một công cụ dùng để tự động hóa việc cấu hình trên nhiều server So với cáccông cụ khác với tính năng tương đương thì Ansible dễ học và dễ tiếp cận hơn rất nhiều

Cơ bản, Ansible gồm các thành phần chính:

• Playbooks: khai báo kịch bản cho các công việc

• Inventory: địa chỉ các node cần được cấu hình

• Tasks: các công việc thực hiện trong playbooks

• Modules: những chức năng hỗ trợ cho việc thực thi các tasks

Trang 25

Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

1.6.1 Cách Ansible hoạt động

Ansible sử dụng kiến trúc agentless để giao tiếp với các máy khác mà không cần agent

Cơ bản nhất là giao tiếp thông qua giao thức SSH trên Linux, WinRM trên Windows hoặcgiao tiếp qua chính API của thiết bị đó cung cấp

Trang 26

Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

2-1024x578.png" \* MERGEFORMATINET INCLUDEPICTURE

"https://cloudcraft.info/wp-content/uploads/2018/10/gioi-thieu-ansible-2-1024x578.png" \*

MERGEFORMATINET INCLUDEPICTURE

"https://cloudcraft.info/wp-content/uploads/2018/10/gioi-thieu-ansible-2-1024x578.png" \* MERGEFORMATINETINCLUDEPICTURE "https://cloudcraft.info/wp-content/uploads/2018/10/gioi-thieu-ansible-

2-1024x578.png" \* MERGEFORMATINET INCLUDEPICTURE

"https://cloudcraft.info/wp-content/uploads/2018/10/gioi-thieu-ansible-2-1024x578.png" \*

MERGEFORMATINET INCLUDEPICTURE

"https://cloudcraft.info/wp-content/uploads/2018/10/gioi-thieu-ansible-2-1024x578.png" \* MERGEFORMATINETINCLUDEPICTURE "https://cloudcraft.info/wp-content/uploads/2018/10/gioi-thieu-ansible-

2-1024x578.png" \* MERGEFORMATINET INCLUDEPICTURE

"https://cloudcraft.info/wp-content/uploads/2018/10/gioi-thieu-ansible-2-1024x578.png" \*

MERGEFORMATINET INCLUDEPICTURE

"https://cloudcraft.info/wp-content/uploads/2018/10/gioi-thieu-ansible-2-1024x578.png" \* MERGEFORMATINETINCLUDEPICTURE "https://cloudcraft.info/wp-content/uploads/2018/10/gioi-thieu-ansible-

2-1024x578.png" \* MERGEFORMATINET INCLUDEPICTURE

"https://cloudcraft.info/wp-content/uploads/2018/10/gioi-thieu-ansible-2-1024x578.png" \*

MERGEFORMATINET INCLUDEPICTURE

"https://cloudcraft.info/wp-content/uploads/2018/10/gioi-thieu-ansible-2-1024x578.png" \* MERGEFORMATINETINCLUDEPICTURE "https://cloudcraft.info/wp-content/uploads/2018/10/gioi-thieu-ansible-

2-1024x578.png" \* MERGEFORMATINET

Trang 27

Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

Hình 2.13 Kiến trúc hoạt động của Ansible

Ansible có 2 loại server là control machine và node Control machine là máy có tráchnhiệm quản lý các node con trong hệ thống Đây cũng là máy lưu trữ các thông tin về cácnode, playbook và các script cần dùng để triển khai trên các node khác qua giao thức SSH.Ansible hoạt động bằng cách kết nối tới các node trong file inventory mặc định bằngSSH Sau khi kết nối, Ansible sẽ gửi các chương trình nhỏ được gọi là Ansible Modules tớicác host xác định Các module này là các mô hình tài nguyên của trạng thái mong muốn của

hệ thống và không yêu cầu cơ sở dữ liệu, máy chủ Sau khi thực thi, các module này sẽ đượcxoá khỏi các host

Ansible có thể giao tiếp với rất nhiều platform, OS và loại thiết bị khác nhau Từ Ubuntu,CentOS, VMware, Windows cho tới AWS, Azure, các thiết bị mạng Cisco và Juniper…, vàhoàn toàn không cần agent khi giao tiếp làm tăng tính tiện dụng của Ansible do không cầnphải setup bảo trì agent trên nhiều host Có thể coi đây là một thế mạnh của Ansible so với cáccông cụ có cùng chức năng như Chef, Puppet, SaltStack

1.6.2 Ứng dụng của Ansible

Ansible có rất nhiều ứng dụng trong triển khai phần mềm và quản trị hệ thống

• Provisioning: Khởi tạo VM, container hàng loạt trong môi trường cloud dựa trên API(OpenStack, AWS, Google Cloud, Azure…)

• Configuration Management: Quản lý cấu hình tập trung các dịch vụ tập trung, không cầnphải chỉnh sửa cấu hình trên từng server

• Application Deployment: Triển khai ứng dụng hàng loạt, quản lý hiệu quả vòng đời củaứng dụng từ giai đoạn lập trình cho tới sản phẩm

• Security & Compliance: Quản lý các chính sách về an toàn thông tin một cách đồng bộtrên nhiều môi trường và sản phẩm khác nhau (chính sách triển khai, cấu hình firewallhàng loạt trên nhiều server…)

1.6.3 YAML

Playbook Ansible được viết theo định dạng cụ thể được gọi là YAML File YAML đượcdùng để thể hiện dữ liệu Dưới đây là so sánh nhanh dữ liệu mẫu ở ba định dạng khác nhau

Hình 2.14 So sánh các Data Model

Trong YAML có 3 cách để biểu diễn giá trị:

• Key Value Pair (Cặp khoá vs giá trị): Dữ liệu được thể hiện bởi kiểu khoá và giá trị (key vàvalue) Trong YAML, khóa và giá trị được phân tách bằng dấu hai chấm (:) Luôn phải cókhoảng trắng theo sau dấu hai chấm

Trang 28

Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

• Dạng dict trong YAML: Dạng này chỉ cần biểu diễn khoảng trắng trước các thuộc tính củaobject

Ví dụ ở đây ta có một object là Banana Trong đó có 3 thuộc tính là calories, fat và carbs

Điểm khác biệt của dạng Dict và Array là các thuộc tính liệt kê dạng dict thì không có thứ

tự Trong khi Array thì ngược lại Ví dụ:

Trang 29

Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

Hình 2.15 Sự khác nhau giữa Dictionary và Array/List trong YAML

1.6.4 Inventory

Đây là nơi sẽ chứa tên các node hay địa chỉ IP muốn thực thi Playbook sẽ có 1 thuộc tính

là hosts, đấy chính là nơi khai báo tên Server Mặc đình file Inventory là /etc/ansible/hosts

Ví dụ một file inventory đơn giản:

#Sample Inventory File

- [all_servers:children] là cách khai báo nhóm của các nhóm với nhau

Ansible còn cung cấp một số params phục vụ cho việc truy cập vào Server đã khai báotrong inventory file dễ dàng hơn

• Port

badwolf.example.com:5309

Trang 30

Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

jumper ansible_port=5555 ansible_host=192.0.2.50

• Host variables

[atlanta]

host1 http_port=80 maxRequestsPerChild=808

host2 http_port=303 maxRequestsPerChild=909

• System: Bao gồm các module như User, Group, Hostname, Systemd, Service, v.v

• Commands: Thường có module con như Command, Expect, Raw, Script, Shell, v.v

• Files: Các module làm việc với file như Copy, Find, Lineinfile, Replace, v.v

• Database: Ansbile cũng hỗ trợ mạnh mẽ những module làm việc với database nhưMongodb, Mssql, Mysql, Postgresql, Proxysql, v.v

• Cloud: Ansible cũng kết hợp với các dịch vụ cloud nổi tiếng như Amazon, Google, Docker,VMware, Digital Ocean, v.v

• Windows: win_copy, win_command, win_domain, win_file, win_shell

1.6.6 Playbooks

Trong playbooks sẽ chứa một tập hợn các activities (hoạt động) hay các tasks (nhiệm vụ)

sẽ được chạy trên một hay một nhóm servers Trong đó task là một hành động duy nhất đượcthực hiện trên server, ví dụ như cài gói Service nào đó, hay bật tắt Service

Xem thử ví dụ một playbook đơn giản:

# Simple Ansible Playbook1.yml

Trang 31

Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

nhiệm vụ đó trên nhiều server thì chỉ cần liệt kê tên server hay tên group server Khai báo tênserver hay group server sẽ nằm trong phần inventory

Cuối cùng, khi đã viết xong một playbook, để chạy nó, Ansible cung cấp cú pháp như sau:

Cũng giống như các ngôn ngữ lập trình khác, biến được sử dụng để lưu trữ các giá trị và

có thể thay đổi giá trị được Để khai báo biến, chúng ta sẽ sử dụng thuộc tính vars mà Ansible

name: Print my car model

command: echo "My car's model is {{ car_model }}"

name: Print my country

command: echo "I live in the { { country_name }}"

Trong đó, car_model sẽ là key, "BMW M3" sẽ là value Bên dưới để sử dụng biến car_model

ta sử dụng cặp dấu ngoặc nhọn và tên biến {{ car_model }}

Trang 32

Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

Ví dụ ta có bài toán như sau: kiểm tra trạng thái của service httpd, nếu start thất bại thì gửimail thông báo cho admin

#Sample ansible playbook.yml

subject: Service Alert

body: "Service is down"

when: command_output.stdout.find("down") != -1

Nhờ vào thuộc tính Register, kết quả trả về sẽ được chứa vào biến command_output Từ

đó ta sử dụng tiếp các thuộc tính của biến command_output là stdout.find để tìm chữ "down"

có xuất hiện trong nội dung trả về không Nếu không tìm thấy thì kết quả sẽ là -1

- name: Install all service

yum: name="{{ item }}" state=present

Handlers giúp thực thi các lệnh khi có sự thay đổi xảy ra với với các task được notify

Ở ví dụ dưới, khi file index.html thay đổi thì mới thực thi Handlers

Trang 33

Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

- name: deploy html file

Trang 34

Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

INCLUDEPICTURE

Trang 35

"https://drive.google.com/uc?id=1ps-Báo cáo DATN Đại Học Chương 2 Tự động hoá IT Automation với Ansible

Vm9BkfdlA_2Thm7TW9nuEDSJPJXx4&export=download" \* MERGEFORMATINET

Hình 2.16 Ansible Role

Trang 36

Báo cáo DATN Đại Học Chương 3 Giải pháp Consul

GIẢI PHÁP CONSUL

1.7 Service Discovery

Trong một ứng dụng truyền thống chạy trên phần cứng vật lý, các vị trí mạng của cácinstance service là tương đối tĩnh Ngược lại, trong các ứng dụng microservices hiện đại đượcxây dựng và triển khai trên nền tảng điện toán đám mây, vị trí mạng của các dịch vụ thay đổilinh động Do đó, việc truy tìm dịch vụ là một nhiệm vụ khó khăn hơn rất nhiều, thể hiệntrong sơ đồ sau đây

Trang 37

Báo cáo DATN Đại Học Chương 3 Giải pháp Consul

Trang 38

"https://techmaster.vn/media/fileman/Uploads/ImageBlog/microservices-la-gi-26102015-Báo cáo DATN Đại Học Chương 3 Giải pháp Consul

1.png" \* MERGEFORMATINET

Hình 3.17 Khó khăn của việc truy tìm dịch vụ trong ứng dụng Microservices

Khi một Service client tìm kiếm một dịch vụ thông qua REST API bao gồm thông tin địachỉ và port, tuy nhiên trong kiến trúc microservice, các dịch vụ được chạy trên nền tảngcontainer hoặc ảo hoá, các dịch vụ sẽ thực hiện scale liên tục theo nhu cầu nên các thông tinnày sẽ thay đổi, vì vậy đoạn mã của client cần áp dụng một kỹ thuật tìm kiếm phức tạp hơn

Có hai mô hình chủ yếu được sử dụng để truy tìm dịch vụ là: Client-side Discovery vàServer-side Discovery

Trang 39

Báo cáo DATN Đại Học Chương 3 Giải pháp Consul

Hình 3.18 Client-side Discovery

Mô hình này đối phó với việc vị trí mạng không ổn định của mỗi dịch vụ bằng cách:

• Khi khởi động dịch vụ, ghi vị trí mạng vào Service Registry và xóa bỏ khi thực thể dịch vụnày kết thúc

• Áp dụng kỹ thuật tín hiệu tuần hoàn (heartbeat mechanism) vào việc cập nhật vị trí mạngcủa các dịch vụ

Những hạn chế:

• Sự ràng buộc giữa client với Service Registry

• Cần viết mã lệnh cho client đối với mỗi ngôn ngữ lập trình và framework

1.7.2 Server-side Discovery

Client tạo ra một yêu cầu tới một dịch vụ thông qua một bộ cân bằng tải Bộ cân bằng tải

sẽ truy vấn Service Registry và định tuyến mỗi yêu cầu tới một service instance có sẵn Cũnggiống như mô hình Client-side Discovery, các service instance được đăng ký và hủy đăng kývới Service Registry

Ngày đăng: 09/01/2021, 10:36

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w