Powerful Google developer tools for immediate impact! (2023-24 C)
CI/CD trên Cloud OpenStack tại Viettel Networks | Hà Minh Công, Phạm Tường Chiến
1. CI/CD with OpenStack Cloud
In Viettel Networks
Cong Ha Minh
Chien Pham Tuong
Viettel Networks Engineer
2. Agenda
1. Why CI/CD and Cloud
2. Build CI/CD infrastructure with OpenStack
3. Automate staging environment provision/destroy with OpenStack
4. Autoscale Production Environment with Heat, Ansible
2
3. Why CI/CD & Cloud
3
Problems with previous development process
- Development Problem:
- Code integration nightmare, unexpected breaking old feature
- Repeated manual testing
- Incontrolable code style
- Operation Problem:
- Handy release process
- Fix physical infrastructure
4. CI/CD and Cloud is the solution for these problems
- Automate dev & ops jobs with CI/CD.
- Unified dev, test and prod platform by Containerize.
- Use Cloud for computing resource management and autoscale.
4
Why CI/CD & Cloud
6. Building CI/CD infrastructure
- Requirements:
- High Availability
- Scale on demand
- Flexible
- Our solutions:
- Keepalived + OpenStack volume
- OpenStack Cloud Plugin
- Build tool provided from Docker
image.
6
7. OpenStack Cloud Plugin
7
- Jenkins cloud extension point for OpenStack
- Scaling slaves by check queue length and available
executors stats
8. OpenStack Cloud Plugin
8
- When available executor stats exponential value below
MARGIN value, Jenkins scale additional slaves via
plugins
- Number of slaves spawned related with queue
length(workload) and number of executors per one slave
12. Staging Environment Problems
In Merge Request Build, we need to create staging environment because:
- Some people don’t know how to write automate tests.
- Some complex and messy things is hard to write tests.
- Something need to manual test before merge (UI/UX)
But we need handle some problems:
- When and how create/destroy a staging environment ?
- Conflict when parallel builds in a merge request occurs.
12
13. Staging Environment Problems
To solve this problem, we combined Jenkins,
OpenStack and GitLab
- Use OpenStack Heat to ensure staging stack is created
before deploy build artifact.
- When merge request is accept/close, destroy its staging
stack by accept/close merge request pipeline.
13
14. Staging Environment Problems
To solve this problem, we combined
Jenkins, OpenStack and GitLab
- Use gitlab commit build status and gitlab merge
request commit list to keep track on list Jenkins
builds is running in a merge request
14
15. Staging Environment Problems
To solve this problem, we combined
Jenkins, OpenStack and GitLab
- When new merge request build start, we cancel
old builds by call to Jenkins API Endpoint, then
update build status
15
17. Results
17
Before:
● Manual test, build code
● Shared staging machine
● Deploy 2-4 times/month
● 2-3 days/release, manual deploy script
● Low success rate
● Manual resource management
After:
● Auto test, build by CI pipelines ~10 min
● Isolated staging environment ~20 min deploy
● Continuous Delivery
● Auto deploy, 40 min/release
● High success rate 95%
● Auto scale, 10-15 min response
18. Challenges
- Scaling time is high when compare with container orchestration
- Ansible Dynamic Inventory
- One time build Slave VM?
- Like Travis, Zuul
- Support Non-Containerize Build
- Clean Build Environment
18
Bài trình bày của chúng tôi sẽ bao gồm những nội dung sau:
Tại sao chúng tôi phải áp dụng CI/CD và Cloud vào quy trình phát triển và triển khai phần mềm tại VTNET
Xây dựng hạ tầng CI/CD với OpenStack
Cách tự động hóa quy trình cấp phát và thu thôi môi trường staging với OpenStack
Cách triển khai phần mềm lên môi trường production đảm bảo tự động co dãn tài nguyên với Heat và Ansible
Phần đầu tiên chúng tôi xin trình bày tại sao chúng tôi phải áp dụng CI/CD và Cloud vào môi trường phát triển và triển khai phần mềm,
Trước đây, quy trình cũ của chúng tôi tương đối thô sơ, ít quy trình tự động hóa, nhiều bước cần sự can thiệp của con người dẫn đễn thời gian phát triển và triển khai kéo dài,
phát sinh nhiều lỗi trong quá trình phát triển và triển khai.
Ví dụ.
- Trong quá trình phát triển do không áp dụng việc test tự động dẫn đến việc =>việc phát triển có thể gây lỗi các tính năng cũ, chất lượng code kém, không được kiểm soát một cách tự động
- Trong quy trình triển khai, người triển khai phải viết các script deploy và rollback bằng tay mỗi lần deploy dẫn tới hay gặp lỗi.
- Việc triển khai ứng dụng trên hạ tầng tĩnh dẫn tới tài nguyên không có khả năng co dãn, một số hệ thống bị dư thừa hoặc quá tải
Gitlab: v12.0.3
Jenkins: 2.164.1
Docker: 18.09.3
Ansible 2.7.2
OpenStack: Rocky
Gitlab: Quản lí mã nguồn, dự án và cấu hình hệ thống
Docker: Đóng gói phần mềm và đồng nhất các môi trường dev staging prod
Nexus: lưu trữ Docker images
Jenkins: Tự động hóa các quy trình phát triển và triển khai
Ansible: sử dụng để triển khai ứng dụng lên các môi trường, Openstack: Quản lí tài nguyên dev và production
Trong môi trường này , thì Jenkins là thành phần quan trọng trong môi trường CI/CD này, sau đây chúng tôi xin trình bày các chúng tôi xây dựng hạ tầng Jenkins dựa trên Openstack
Sau đây chúng tôi xin trình bày cách chúng tôi xây dựng hệ thống Jenkins CI/CD.
Vì hệ thống Jenkins CI/CD là một thành phần quan trọng trong môi trường phát triển và triển khai phần mềm, nên chúng tôi đặt ra các yêu cầu sau:
- Hệ thống CI/CD cần có tính sẵn sàng cao
- Có khả năng co dãn tài nguyên build đáp ứng hợp lý với các yêu cầu build & deploy của nhiều đơn vị phát triển phần mềm và triển khai phần mềm.
- Có khả năng tích hơp với các hạ tầng và hệ thống sẵn có, phục vụ các yêucầu đa dạng về công cụ, ngôn ngữ và platform khác nhau như Java, Python, Node-angular....
Để đáp ứng các yêu cầu trên, chúng tôi đã áp dụng các giải pháp sau:
- Đảm bảo tĩnh sẵn sàng cao cho Jenkins Master bằng việc sử dụng keepalived để tự động phục hồi Jenkins Master khi có sự cố xảy ra với việc sử dụng các keepalived script start, backup, fail, monitor
- Lưu trữ dữ liệu của Jenkins Master ở OpenStack Volume, khi keepalived thay đổi master node thì các keepalived script sẽ tự động thực hiện việc detach volume này ở master cũ rồi attach volume này vào master mới.
- Cung cấp các build tool thông qua Docker Image như: Ansible docker image, Python docker image, telnet docker image, Java - Maven docker image.... đáp ứng nhu cầu build đa dạng của người dùng mà không cần cài cắm các tool, plugin vào hệ thống Jenkins mỗi khi nhu cầu thay đổi.
- Sau đây chúng tôi xin giói thiệu về giải pháp scale Jenkin slave bằng OpenStack Cloud plugin:
- Đây là giải pháp mà chúng tôi sử dụng để tích hợp Jenkins với OpenStack để tự động cấp phát và thu hồi Jenkins Slave dựa trên nhu cầu build của người dùng đổ về hệ thống Jenkins:
- Plugin này sử dụng các thống kê về tải của hệ thống Jenkins thông qua các metrics:
- Available executor: Số lượng executor đang không thực hiện build.
- Queue length: Số lượng các build đang chờ được Jenkins build khi mà không còn executor nào ở trạng thái available
- Khi tất cả các executor đều đã busy, thì chỉ số available executor sẽ giảm dần về 0. Khi chỉ số này vượt qua giới hạn đã định trước, hệ thống sẽ tiến hành gọi đến OpenStack để sinh ra các slave VM mới.
- Ví dụ trong queue đang có 6 build, 1 slave có 4 executor thì hệ thống sẽ sinh ra 2 slave để thực thi các build đang chờ trong queue
- với các giá trị tham số mặc định, thì chúng tôi thấy rằng thời gian từ lúc hệ thống đầy tải cho đến khi slave VM mới được sinh ra là khoảng 6 phút
- trên đây là cơ chế scale out slave VM khi nhu cầu build cao.
- Khi nhu cầu build vào Jenkins giảm xuống, một số các slave sẽ không nhận được build nào và chuyển sang trạng thái free. Khi 1 số slave ở trạng thái free quá một thời gian định trước, Jenkins sẽ tự động xóa bớt một số slave đang free, cho đến khi hết slave free hoặc số lượng slave giảm xuống giá trị Minimum định trước.
Đây là hình ảnh các slave VM được sinh ra khi tải vào hệ thống Jenkins tăng lên và OpenStack Cloud Plugin hoạt động để scale slave VM mới.
Trên đây chúng tôi đã trình bày về cách chúng tôi xây dựng hạ tầng Jenkins CI/CD dựa trên OpenStack. Sau đây chúng tôi sẽ trình bày cách chúng tôi áp dụng CI/CD vào quá trình phát triển và triển khai phần mềm như thế nào
Đầu tiên tôi sẽ trình bày về luồng tích hợp liên tục CI. Trong luồng này chúng sử dụng 2 Jenkins job là push commit job và merge request job. Push commit job sẽ được trigger khi người phát triển đẩy code của mình lên gitlab repository. Lúc đó Gitlab sẽ đẩy một push event cho Jenkins, khi Jenkin nhận được Push event, nó sẽ tạo ra push commit build thực hiện các công việc: Unit test, code coverage test, checkstyle test, sonarqube scane.
Sau khi các bài test tự động này thực hiện xong, Jenkins sẽ tổng hợp kết quả test rồi gửi kết quả build về mail của người dùng
Tiếp theo là luồng merge request job, merge request job sẽ được trigger khi người phát triển tạo hoặc thay đổi một merge request trên Gitlab. Khi đó gitlab sẽ gửi tới Jenkins 1 merge request event. Jenkins nhận được event này sẽ thực hiện merge request build bao gồm các công việc sau:
- Chạy các bài test tự động như push commit build.
- Build Docker Image từ mã nguồn.
- Đẩy Image lên Nexus.
- Đồng thời gọi đến OpenStack Heatstack API để đảm bảo môi trường staging đã được tạo ra.
- Sau đó Jenkins tạo ra Ansible Inventory chứa thông tin về môi trường staging, sau đó sử dụng Ansible để thực hiện việc stop ứng dụng version cũ rồi triển khai ứng dụng ở version mới lên môi trường staging.
- Cuối cùng thông báo kết quả build merge request và thông tin staging environment qua hệ thống mail.
Như các bạn đã thấy, ở mỗi merge request chúng tôi đều duy trì một môi trường staging riêng biệt. Lý do là bởi vì trong quá trình phát triển chúng tôi cần thực hiện 1 số tác vụ test phức tạp mà chưa thể tự động hóa, mà đòi hỏi manual test mới giải quyết được.
Thì việc phải duy trì môi trường staging như vậy dẫn tới việc chúng tôi sẽ phải giải quyết những vấn đề sau:
- Làm thế nào để cấp phát và thu hồi staging environment.
- Giải quyết conflict về việc sử dụng môi trường staging khi giữa các build thực hiện cùng lúc trong cùng 1 merge request..
Sau đây là cách chúng tôi giải quyết vấn đề staging environment trong Merge request build.
Để giải quyết vấn đề này chúng tôi đã kết hợp giữa Jenkins, Openstack và Gitlab cụ thể là
Vấn đề đầu tiên là làm thế nào để tự động hóa việc cấp phát và thu hồi staging environment:
- Khi chúng tôi build 1 merge request build. chúng tôi sẽ gọi tới Openstack Heat API để đảm bảo 1 staging Stack được tạo ra
- Khi 1 merge request được accept/close thì chúng tôi cũng gọi tới Openstack Heat API để thu hồi staging Stack đã tạo ra trước đó
Để giải quyết vấn đề build conflict thì chúng tôi ghi lại trạng thái các build của 1 MR thông qua gitlab commit status thì khi 1 MR build đang build thì status sẽ là running.
Khi 1 MR build mới chạy nó sẽ xác định xem ngoài nó còn các MR build nào khác thuộc cùng 1 MR này đang chạy để từ đó gọi tơi Jenkins API để stop các MR request cũ hơn nó đang chạy.
Sau đó mới bắt đầu các hoạt động build tiếp theo trong Merge request build.
Vừa rồi chúng tôi đã trình bày cách xây dựng các Jenkins job trong luồng tích hợp liên tục CI. Phần tiếp theo tôi sẽ trình bày về luồng triển khai liên tục CD.
Ở luồng này chúng tôi sẽ có 1 Deploy Production Job được trigger khi maintainer của dự án tạo một tag mới trên Gitlab để tiến hành release ứng dụng.
Khi đó gitlab sẽ gửi tới Jenkins 1 tag event. Khi jenkins nhận được event này nó sẽ trigger 1 build thực hiện các công việc sau đây:
- Lấy mã nguồn nhánh release từ Gitlab
- Chạy các bài test tự động
- Build docker image từ mã nguồn của nhánh release rồi đẩy lên Nexus repository.
- Sau đó Jenkins gọi đến OpenStack để tạm dừng việc autoscale production stack trên OpenStack.
- Sau đó, Jenkins gọi tới OpenStack để lấy dánh sách các VM đang hoạt động của hệ thống production và tiến hành tạo ra Ansible inventory chứa thông tin danh sách các VM này.
- Sau đó Jenkins sử dụng Ansible để tiến hành deploy appllication lên các VM, trong đó docker image được lấy từ Nexus và cấu hình hệ thống được lấy từ gitlab..
- Cuối cùng chúng tôi resume lại việc autoscaling trên OpenStack, rồi thông báo kết quả deploy về người dùng thông qua hệ thống mail.
Sau đây là một số kết quả chúng tôi đã đạt được khi áp dụng CI/CD và Cloud vào việc phát triển và triển khai phần mềm tại VTNET:
Trước đây việc test, build code hoàn toàn bằng tay thì giờ đã hòan toàn tự động, thời gian build chỉ mất khoảng 10 phút
Từ việc các developer phải tự dựng bằng tay ứng dụng để test trên môi trường staging chia sẻ với nhau 1 vài máy test, thì nay môi trường staging đã độc lập với nhau, thời gian dựng lên 1 môi trương staging chỉ khoảng 10 phút
Tần suât deploy cũng tăng lên rất nhiều, từ việc chỉ có thể deploy 2-4 lần trong mỗi tháng thì chúng tôi đã có thể tiến hành deploy liên tục, vài lần 1 ngày, đáp ứng yêu cầu thay đổi phần mềm liên tục theo nhù cầu người dùng.
Bên cạnh đó thời gian chuản bị và tiến hành deploy cũng giảm đáng kể từ 2-3 ngày xuống còn 40 phút.
Do quy trình deploy hoàn toàn tự động thay vì có nhiều bước cần con người thực hiện bằng tay như chuẩn bị script deploy/rollback nên tỉ lệ deploy ứng dụng thành công tăng lên.
Về mặt quản lý tài nguyên thì trước đây chúng tôi hoàn toàn quản lý tài nguyên cho dev và production một cách thủ công thì nay quy trình cấp phát và thu hồi tài nguyên, cũng như co dãn tài nguyên môi trường production được diễn ra hoàn toàn tự động trong vòng từ 10-15 phút.