duy trì một cơ sở mã hóa đa dạng đang phát triển với sự tích hợp liên tục


10

Tôi cần một số trợ giúp với triết lý và thiết kế một thiết lập tích hợp liên tục.

Thiết lập CI hiện tại của chúng tôi sử dụng buildbot. Khi tôi bắt đầu thiết kế nó, tôi đã kế thừa (tốt, không nghiêm túc, vì tôi đã tham gia vào thiết kế của nó một năm trước đó) một nhà xây dựng CI bespoke được thiết kế để chạy toàn bộ công trình cùng một lúc, qua đêm. Sau một thời gian, chúng tôi quyết định rằng điều này là không đủ, và bắt đầu khám phá các khung CI khác nhau, cuối cùng chọn buildbot. Một trong những mục tiêu của tôi khi chuyển sang buildbot (bên cạnh việc tận hưởng tất cả các tính năng bổ sung của tiếng rít) là khắc phục một số bất cập của người xây dựng hàng đêm bespoke của chúng tôi.

Hài hước cho tôi một lúc, và để tôi giải thích những gì tôi được thừa hưởng. Cơ sở mã cho công ty của tôi là gần 150 ứng dụng Windows c ++ duy nhất, mỗi ứng dụng có phụ thuộc vào một hoặc nhiều tá thư viện nội bộ (và nhiều thư viện của bên thứ 3). Một số các thư viện này phụ thuộc lẫn nhau và có các ứng dụng phụ thuộc (trong khi chúng không liên quan gì đến nhau) phải được xây dựng với cùng một bản dựng của thư viện đó. Một nửa trong số các ứng dụng và thư viện này được coi là "di sản" và không thể truy cập được và phải được xây dựng với một số cấu hình riêng biệt của trình biên dịch IBM (trong đó tôi đã viết các lớp con duy nhất Compile) và nửa còn lại được xây dựng với studio trực quan.ShellCommands, vì không có hỗ trợ cho VSS).

Nhà xây dựng hàng đêm ban đầu của chúng tôi chỉ đơn giản là lấy nguồn cho mọi thứ và xây dựng công cụ theo một thứ tự nhất định. Không có cách nào để chỉ xây dựng một ứng dụng duy nhất, hoặc chọn một bản sửa đổi hoặc để nhóm các thứ. Nó sẽ ra mắt các máy ảo để xây dựng một số ứng dụng. Nó không mạnh lắm, nó không thể phân phối được. Nó không thể mở rộng khủng khiếp. Tôi muốn có thể khắc phục tất cả những hạn chế này trong buildbot.

Cách tôi đã làm điều này ban đầu là tạo các mục cho từng ứng dụng mà chúng tôi muốn xây dựng (tất cả 150 trong số chúng), sau đó tạo các trình lập lịch được kích hoạt có thể xây dựng các ứng dụng khác nhau thành các nhóm, và sau đó đưa các nhóm đó theo lịch trình xây dựng hàng đêm tổng thể. Chúng có thể chạy trên các nô lệ chuyên dụng (không cần thêm máy ảo) và nếu tôi muốn, tôi có thể chỉ cần thêm nô lệ mới. Bây giờ, nếu chúng ta muốn thực hiện xây dựng đầy đủ theo lịch trình, đó chỉ là một cú nhấp chuột, nhưng chúng ta cũng có thể xây dựng chỉ một ứng dụng mà chúng ta mong muốn.

Tuy nhiên, có bốn điểm yếu của phương pháp này. Một là mạng phụ thuộc phức tạp của cây nguồn của chúng tôi. Để đơn giản hóa việc bảo trì cấu hình, tất cả các trình tạo được tạo từ một từ điển lớn. Các phần phụ thuộc được truy xuất và xây dựng theo kiểu không mạnh mẽ khủng khiếp (cụ thể là, khóa các thứ nhất định trong từ điển mục tiêu xây dựng của tôi). Thứ hai là mỗi bản dựng có từ 15 đến 21 bước xây dựng, rất khó để duyệt và xem trong giao diện web và vì có khoảng 150 cột, sẽ tải mãi mãi (suy nghĩ từ 30 giây đến nhiều phút). Thứ ba, chúng tôi không còn tự động phát hiện các mục tiêu xây dựng (mặc dù, nhiều như một trong những đồng nghiệp của tôi đã nói với tôi về điều này, tôi không thấy những gì nó đưa chúng tôi ở nơi đầu tiên). Cuối cùng,

Bây giờ, chuyển sang phát triển mới, chúng tôi bắt đầu sử dụng g ++ và lật đổ (không chuyển kho lưu trữ cũ, làm phiền bạn - chỉ cho các công cụ mới). Ngoài ra, chúng tôi đang bắt đầu thực hiện nhiều thử nghiệm đơn vị hơn ("nhiều hơn" có thể đưa ra hình ảnh sai ... nó giống như bất kỳ ) và thử nghiệm tích hợp (sử dụng python). Tôi đang có một thời gian khó khăn để tìm ra làm thế nào để phù hợp với những điều này vào cấu hình hiện tại của tôi.

Vì vậy, tôi đã sai ở đâu về mặt triết học ở đây? Làm cách nào tôi có thể tiến lên tốt nhất (với buildbot - đó là mảnh ghép duy nhất mà tôi có giấy phép hoạt động) để cấu hình của tôi thực sự có thể duy trì được? Làm thế nào để tôi giải quyết một số điểm yếu của thiết kế? Điều gì thực sự hoạt động về mặt chiến lược CI cho các cơ sở mã lớn, phức tạp (có thể là quá mức)?

BIÊN TẬP:

Tôi nghĩ rằng tôi đã giải thích vấn đề của mình, nhưng rõ ràng tôi không đủ rõ ràng. Tôi không tìm kiếm đề xuất thay đổi nền tảng CI. Nó sẽ không xảy ra, và câu trả lời cho thấy rằng sẽ không được chấp nhận. Điều tôi muốn biết là cách người khác quản lý các cơ sở mã phức tạp bằng CI. Tôi có một các sản phẩm khác nhau bình phương , và tôi có sự phụ thuộc rải rác trong gió, và tất cả chúng đều khác nhau. Đây là những gì tôi muốn biết làm thế nào để đối phó với.


Tôi cũng muốn biết câu trả lời cho điều này. Môi trường của chúng tôi không phức tạp như của bạn, nhưng chúng tôi có sự phụ thuộc của sự phụ thuộc của phụ thuộc (trong trường hợp của dự án thiết lập, nó có phụ thuộc sâu bốn lớp). Tôi không biết mỗi dự án nên là một dự án CI hay tôi chỉ nên sử dụng tệp .sln của Visual Studio để chăm sóc nó cho tôi để tôi không phải tạo lại cây phụ thuộc cho từng dự án (và dự án trong tương lai).
moswald

Không thể xây dựng trên máy cục bộ của bạn làm cho nhiệm vụ máy chủ CI của bạn trở nên quan trọng đối với doanh nghiệp của bạn. Bạn có thể muốn suy nghĩ lại về điều này.
Thorbjørn Ravn Andersen

Câu trả lời:


3

Mặc dù tôi chưa gặp phải tình huống tồi tệ như bạn mô tả, tôi vẫn đang duy trì cấu hình CI với hàng chục thành phần, giữa đó có một số phụ thuộc 'đơn giản'. Tôi hy vọng rằng phương pháp của tôi có thể cung cấp cho bạn một số gợi ý để tiếp tục. Vấn đề chắc chắn không chỉ liên quan đến sự lựa chọn máy chủ CI, mà còn liên quan đến quá trình xây dựng tổng thể và cấu trúc dự án.

Tôi sẽ chia vấn đề thành 2 phần: Tòa nhà và CI.

Xây dựng

Đối với "Xây dựng" tôi có nghĩa là quá trình, thay đổi mã nguồn trên tay thành cổ vật cuối cùng. Công ty chúng tôi chủ yếu sử dụng Java trong phát triển và công cụ xây dựng mà chúng tôi sử dụng là Maven. Bạn có thể sẽ không thể sử dụng điều đó do bản chất của dự án của bạn, nhưng có một số khái niệm có giá trị trong Maven đáng chú ý:

1) Trong thế giới Maven, mỗi tạo tác (một lib, chương trình thực, v.v.) cần phải được phân tách rõ ràng và tách rời. Sự phụ thuộc giữa tạo tác nên rõ ràng. Tôi nên nhấn mạnh, sự phụ thuộc lộn xộn, đặc biệt là sự phụ thuộc vòng tròn giữa các tạo phẩm xây dựng của bạn sẽ làm cho quá trình xây dựng trở nên lộn xộn.

Ví dụ, tôi đã thấy một số dự án java trước đó, mặc dù sau toàn bộ quá trình xây dựng có một số JAR (bạn có thể coi đó là lib / dll trong Java) được xây dựng, nhưng thực tế chúng phụ thuộc lẫn nhau. Giống như, A.jar đang sử dụng những thứ trong B.jar và ngược lại. Kiểu 'mô đun hóa' như vậy là hoàn toàn vô nghĩa. A.jar và B.jar luôn cần được triển khai và sử dụng cùng nhau. Hàm ý là, sau này nếu bạn muốn tách chúng thành các dự án khác nhau (ví dụ để sử dụng lại trong các dự án khác), bạn sẽ không thể làm như vậy, vì bạn không thể xác định dự án nào, A hoặc B, để xây dựng trước.

Đúng, nó cần được phục vụ trong thiết kế phần mềm của bạn, nhưng tôi luôn tin rằng, thay vì trả thời gian để làm cho một công cụ / mô hình xây dựng phức tạp hoạt động trong một dự án lộn xộn, tôi muốn dành thời gian để sắp xếp lại thiết kế để sử dụng mô hình xây dựng đơn giản.

2) Phụ thuộc nên được khai báo. Có rất nhiều quá trình xây dựng mà tôi đã thấy trước đây, chúng bao gồm tất cả các lib mà nó cần tại địa phương trong dự án. Nó sẽ làm cho quá trình xây dựng trở nên cực kỳ rắc rối nếu một số lib trong thực tế là các tạo phẩm khác mà bạn cần xây dựng.

3) Lưu trữ "tập trung" cho các tạo phẩm để nhận phụ thuộc hoặc để triển khai các tạo phẩm sau khi được biên dịch. Nó không cần phải được "tập trung" cho toàn bộ văn phòng (sẽ rất tuyệt nếu có), chỉ cần một thư mục địa phương sẽ ổn.

Chi tiết hơn về 2 và 3. Chỉ cần đưa ra một ví dụ, tôi đã bắt gặp một dự án liên quan đến 3 dự án độc lập. Mỗi dự án được xây dựng dựa trên nguồn, cộng với các lib dưới thư mục lib / trong thư mục nguồn. Dự án A sẽ xây dựng một số lib, lần lượt được sử dụng bởi dự án B và C. Có một số nhược điểm: quy trình xây dựng phức tạp và khó tự động hóa hơn; kiểm soát nguồn đang trở nên cồng kềnh với các JAR trùng lặp không cần thiết được sử dụng lại trong các dự án khác nhau

Trong thế giới của Maven, những gì nó được thực hiện là, dự án B và C không thực sự chứa A.jar (và các phụ thuộc khác, như lib bên thứ 3 khác) trong nguồn dự án. Đó là tuyên bố. Ví dụ, trong cấu hình xây dựng của dự án B, nó chỉ cần khai báo rằng nó cần: A.lib v1.0, xyz.lib v2.1, v.v., và tập lệnh xây dựng sẽ tra cứu lib từ /A/1.0/A. bình và /xyz/2.1/xyz.lib

Đối với thế giới không phải Maven, thư mục giả này chỉ cần là một hoặc hai thư mục có cấu trúc thư mục đã thỏa thuận. Bạn có thể đặt tất cả các lib của bên thứ 3 vào một vị trí chia sẻ và cho phép các nhà phát triển đồng bộ hóa hoặc sao chép vào các máy cục bộ của họ. Trong các dự án C ++ của tôi, tôi đã làm nhiều năm trước đây, những gì tôi đang làm là đặt lib và tiêu đề thành $ {artifact_dir} / lib_name / ver và với artifact_id được khai báo là biến môi trường.

Khi dự án A được xây dựng, nó sẽ có một bản sao kết quả của nó trong artifact_dir đó, để khi chúng tôi xây dựng dự án B, B có thể tự động nhận kết quả của A mà không cần sao chép thủ công.

4) Phát hành không thể thay đổi. Khi bạn phát hành A.lib 1.0, thế là xong, bạn sẽ không mong đợi nội dung của A.lib 1.0 thay đổi sau 1 tháng chỉ có một số sửa lỗi. Trong trường hợp như vậy, nó phải là A.lib 1.1. Cổ vật của một cơ sở mã thay đổi sẽ xem xét một "phiên bản" đặc biệt, mà trong Maven, chúng tôi gọi nó là ảnh chụp nhanh.

Phát hành không đột biến là một vấn đề đạo đức hơn. Nhưng những gì nó đã giải quyết rất rõ ràng: Khi bạn có nhiều dự án, sử dụng cùng một lib, bạn biết phiên bản lib nào bạn đang sử dụng và bạn sẽ chắc chắn rằng, cùng một phiên bản lib được sử dụng trong các dự án khác nhau, thực sự giống nhau . Tôi nghĩ rằng nhiều người trong chúng ta đã gặp phải vấn đề: Tại sao dự án X và Y đều sử dụng lib A nhưng kết quả xây dựng lại khác nhau? (và hóa ra rằng lib A sử dụng bởi X và Y trên thực tế khác nhau sau khi đào sâu vào nội dung hoặc kích thước tệp của lib).


Tất cả những điều này đảm bảo rằng các dự án của bạn có thể xây dựng độc lập, không cần nhiều thủ thuật thủ công như, xây dựng dự án A trước, sao chép A.lib sang dự án B, sau đó xây dựng dự án B ...

Sau khi trải qua một bài tập như thế này, ví dụ, khi bạn xây dựng dự án A, nó sẽ cố gắng lấy các phần phụ thuộc từ bộ lưu trữ tạo tác tập trung. Trong trường hợp không tìm thấy một số phụ thuộc (là các dự án khác của công ty bạn, ví dụ dự án B), bạn cần làm gì, lấy nguồn của dự án B, xây dựng nó (sẽ triển khai vào bộ lưu trữ tập trung khi thành công) và sau đó xây dựng dự án A một lần nữa.


CI

Với một hệ thống xây dựng dễ dàng, với sự phụ thuộc rõ ràng, CI sẽ dễ dàng hơn nhiều. Tôi sẽ mong đợi máy chủ CI của bạn phục vụ các yêu cầu sau:

1) Giám sát kiểm soát nguồn, chỉ kiểm tra + xây dựng khi có thay đổi trong nguồn

2) Có thể thiết lập các phụ thuộc giữa các dự án

Với sự phụ thuộc rõ ràng cho các dự án, bạn chỉ cần thiết lập các dự án trong CI theo dự án thực tế của mình, thiết lập sự phụ thuộc dự án CI theo sự phụ thuộc của dự án. Máy chủ CI của bạn nên được thiết lập để xây dựng các dự án phụ thuộc trước khi xây dựng bất kỳ dự án nào (và tất nhiên, việc xây dựng chỉ xảy ra nếu nguồn dự án thực sự có thay đổi).

Nếu mọi thứ đều ổn, bạn nên có một CI khổng lồ, phức tạp, nhưng vẫn có thể quản lý được (và thậm chí quan trọng hơn, một cấu trúc dự án có thể quản lý được)


Tôi thích câu trả lời này sẽ đi đến đâu, nhưng bạn có thể đi sâu vào chi tiết hơn trong phần 'tòa nhà' không? Đó là, đưa ra một số ví dụ, giải thích một số khái niệm đầy đủ hơn, công phu hơn.
Nate

hm ... thích phần nào? Tôi cố gắng chỉnh sửa bài để cung cấp thêm chi tiết của từng phần. Sẽ tốt hơn nếu bạn có thể cho tôi biết phần nào bạn cảm thấy cần phải xây dựng. Nhân tiện, nếu bạn cũng đang sử dụng Java, hãy xem trong maven.apache.org. Maven có thể không phải là điều dễ dàng nhất để áp dụng nhưng nó buộc bạn phải làm cho mọi thứ của bạn sạch sẽ và có tổ chức.
Adrian Shum

1

Điều gì đã làm việc trong các tình huống tương tự đối với tôi:

  • Trừu tượng hóa cấp ứng dụng bằng cách chuyển một số phần của bản dựng thành các ứng dụng xây dựng chuyên dụng (trong trường hợp của chúng tôi là các tập lệnh PHP được gọi từ bản dựng chính). Điều này có thể giảm vài chục dòng bước xây dựng thành một bước xây dựng.
  • Trừu tượng cấp độ xây dựng bằng cách tạo các tập lệnh xây dựng phụ được khởi chạy từ tập lệnh xây dựng chính. Không biết liệu nó có liên quan đến buildbot không (không có kinh nghiệm với sản phẩm đó).

Tôi sẽ đề nghị bạn coi bản thân nó là một dự án phát triển phần mềm. Điều này có nghĩa là bạn cần phải mô đun hóa cơ sở mã xây dựng và viết một số thử nghiệm tự động cho nó (ví dụ: xây dựng một số sửa đổi đã biết và kiểm tra xem nó có tạo ra kết quả chính xác không).


0

Tôi sẽ coi Jenkins là một máy chủ CI, bạn có thể xem các tính năng ở đây:

https://wiki.jenkins-ci.org/display/JENKINS/Meet+Jenkins

Tại sao? Thật dễ dàng để cài đặt, nó có một giao diện tuyệt vời, dễ dàng cấu hình và mở rộng và có RẤT NHIỀU plugin sẵn sàng cho hầu hết mọi thứ:

https://wiki.jenkins-ci.org/display/JENKINS/Plugins

Hãy thử một lần :)


2
Tôi cảm thấy rằng bạn đọc tiêu đề cho câu hỏi của tôi, nhưng không đọc cơ thể ... Tôi không tìm kiếm một đề xuất sản phẩm. Tôi đã chọn một sản phẩm. Tôi đang tìm cách tổ chức một thiết lập CI phức tạp.
Nate

Nate, tôi đã đọc tất cả bài đăng của bạn và tôi nghĩ rằng bạn đã chọn sai sản phẩm, đó là lý do tại sao tôi đề xuất Jenkins. Tôi sử dụng Jenkins tại nơi làm việc để thử nghiệm các loại sản phẩm C ++ khác nhau (thậm chí các thử nghiệm được viết bằng nhiều ngôn ngữ) với phân cụm trên nhiều máy và nó chạy rất tốt. Nó rất dễ dàng để quản lý và cấu hình. Thực sự, hãy thử nó :)
Patrizio Rullo

Nhìn vào bài đăng trên blog này quá: vperic.blogspot.com/2011/05/ Khăn
Patrizio

0

Bây giờ chúng tôi sử dụng Go by Th ThinkWorks trước đó, chúng tôi đã sử dụng CruiseControl.Net . Thật hữu ích khi xem xét chúng tôi có hai đội cách nhau nửa vòng trái đất và có sự khác biệt lớn về múi giờ giữa chúng tôi.

Chúng tôi đang quản lý nhiều dự án và hầu hết các nhiệm vụ liên quan đến sự chồng chéo giữa hai nhà phát triển ở cả hai phía trên toàn cầu, vì vậy chúng tôi phải lưu ý rằng tất cả các tệp không nên phá vỡ bản dựng của người khác.

Ngoài ra việc quản lý trở nên dễ dàng hơn với Go và là một công cụ xử lý nhanh Agile, nó đã khiến chúng tôi bớt đau đầu hơn sau khi chúng tôi cài đặt nó. Kiểm tra cũng đã được tích hợp với Go.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.